如何检查一个DOM元素是否是另一个DOM元素的子元素?有内置的方法吗?例如,类似:
if (element1.hasDescendant(element2))
要么
if (element2.hasParent(element1))
如果没有,那么有什么想法怎么做?它还需要跨浏览器。我还应该提到,孩子可以嵌套在父级以下的多个级别。
如何检查一个DOM元素是否是另一个DOM元素的子元素?有内置的方法吗?例如,类似:
if (element1.hasDescendant(element2))
要么
if (element2.hasParent(element1))
如果没有,那么有什么想法怎么做?它还需要跨浏览器。我还应该提到,孩子可以嵌套在父级以下的多个级别。
Answers:
更新:现在有一种实现此目标的本地方法。Node.contains()
。在评论中也提到了答案。
旧答案:
使用该parentNode
属性应该可以。从跨浏览器的角度来看,它也是非常安全的。如果已知这种关系是一级的,则可以简单地检查一下:
if (element2.parentNode == element1) { ... }
如果可以将孩子任意地嵌套在父对象的深处,则可以使用类似于以下内容的函数测试这种关系:
function isDescendant(parent, child) {
var node = child.parentNode;
while (node != null) {
if (node == parent) {
return true;
}
node = node.parentNode;
}
return false;
}
Node.contains
(尽管没有caniuse页面)
您应该使用Node.contains
,因为它现在是标准的,并且在所有浏览器中都可用。
https://developer.mozilla.org/zh-CN/docs/Web/API/Node.contains
var parent = document.getElementById('menu'); var allElements = document.getElementsByTagName('a'); if (parent.contains(allElements[i]) { alert('Link is inside meni'); }
我只需要分享“我的”。
虽然概念一样亚萨的答案(受益于相同的跨浏览器的兼容性,甚至IE6),这是一个很多更小,非常适合对尺寸为溢价和/或当它不需要经常。
function childOf(/*child node*/c, /*parent node*/p){ //returns boolean
while((c=c.parentNode)&&c!==p);
return !!c;
}
..或单线(仅64个字符!):
function childOf(c,p){while((c=c.parentNode)&&c!==p);return !!c}
用法:
childOf(child, parent)
返回布尔值true
| false
。
说明:
while
只要while条件求值为,就求值true
。
该&&
(AND)运算符返回此布尔真/假后评估的左侧和右侧,但只有当左手侧是真实的(left-hand && right-hand
)。
(&&
)的左侧是:(c=c.parentNode)
。
这将首先分配parentNode
的c
到c
,然后与运营商将评价所形成的c
一个布尔值。
由于如果在没有任何父母的情况下parentNode
返回null
并null
转换为false
,则在没有父母的情况下while循环将正确停止。
(的&&
)右侧为:c!==p
。
的!==
比较操作符是“ 不完全等于”。因此,如果孩子的父母不是您指定的父母(您指定的父母)true
,但是如果孩子的父母是父母,那么它将评估为false
。
因此,如果 c!==p
计算结果为false,则&&
运算符将返回false
while条件,并且while循环停止。(请注意,无需使用while主体,并且;
需要使用分号。)
因此,当while循环结束时,它是找到父项c
的节点(不是null
),或者是null
(当循环运行到末尾而没有找到匹配项时)。
因此,我们简单地return
这一事实(换算为布尔值,该节点的代替)其中:return !!c;
:所述!
(NOT
操作者)反转的布尔值(true
变false
,反之亦然)。
!c
在将c
值反转之前,先将(节点或null)转换为布尔值。因此,添加second !
(!!c
)会将这个false转换回 true(这就是为什么!!
通常使用double 来将任何内容“转换为boolean”的原因)。
附加:
函数的主体/有效负载非常小,根据情况(例如,当它不经常使用并且仅在代码中出现一次),甚至可以省略该函数(包装),而仅使用while循环:
var a=document.getElementById('child'),
b=document.getElementById('parent'),
c;
c=a; while((c=c.parentNode)&&c!==b); //c=!!c;
if(!!c){ //`if(c)` if `c=!!c;` was used after while-loop above
//do stuff
}
代替:
var a=document.getElementById('child'),
b=document.getElementById('parent'),
c;
function childOf(c,p){while((c=c.parentNode)&&c!==p);return !!c}
c=childOf(a, b);
if(c){
//do stuff
}
!==
)可通过使编译器清楚可以跳过松散的相等比较中会发生的类型检查和可选的隐式转换步骤来提高速度,从而提高了速度(通过更准确地描述我们想发生,这对程序员也有好处)。从撰写本文时,我似乎还记得,松散的比较(!=
)要么很容易出错,要么在某些旧版浏览器中根本不起作用(我怀疑它是在IE6中,但我忘记了)。
另一个未提及的解决方案:
var parent = document.querySelector('.parent');
if (parent.querySelector('.child') !== null) {
// .. it's a child
}
元素是否是直接子元素都无关紧要,它可以在任何深度使用。
或者,使用.contains()
方法:
var parent = document.querySelector('.parent'),
child = document.querySelector('.child');
if (parent.contains(child)) {
// .. it's a child
}
看一下Node#compareDocumentPosition。
function isDescendant(ancestor,descendant){
return ancestor.compareDocumentPosition(descendant) &
Node.DOCUMENT_POSITION_CONTAINS;
}
function isAncestor(descendant,ancestor){
return descendant.compareDocumentPosition(ancestor) &
Node.DOCUMENT_POSITION_CONTAINED_BY;
}
其他关系包括DOCUMENT_POSITION_DISCONNECTED
,DOCUMENT_POSITION_PRECEDING
,和DOCUMENT_POSITION_FOLLOWING
。
IE <= 8不支持。
您可以使用contains方法
var result = parent.contains(child);
或者您可以尝试使用compareDocumentPosition()
var result = nodeA.compareDocumentPosition(nodeB);
最后一个功能更强大:它返回一个位掩码作为结果。
我遇到了一段很棒的代码,检查一个元素是否是另一个元素的子元素。我必须使用它,因为IE不支持.contains
element方法。希望这对其他人也有帮助。
下面是功能:
function isChildOf(childObject, containerObject) {
var returnValue = false;
var currentObject;
if (typeof containerObject === 'string') {
containerObject = document.getElementById(containerObject);
}
if (typeof childObject === 'string') {
childObject = document.getElementById(childObject);
}
currentObject = childObject.parentNode;
while (currentObject !== undefined) {
if (currentObject === document.body) {
break;
}
if (currentObject.id == containerObject.id) {
returnValue = true;
break;
}
// Move up the hierarchy
currentObject = currentObject.parentNode;
}
return returnValue;
}