BubblyPoker's Blog

如何判断一个节点是另一节点的子节点?

方法有三

  1. DOM结构向上遍历
  2. node.contains方法
  3. node.compareDocumentPosition方法

向上遍历

1
2
3
4
5
6
7
8
9
10
11
function contains (refNode, otherNode) {
let parent = otherNode.parentNode
while (parent !== null) {
if (parent === refNode) {
return true
} else {
parent = parent.parentNode
}
}
return false
}

就是从otherNode开始向上遍历DOM结构,递归获取parentNode,并检测是否和refNode相等

contains

语法

refNode.contains(otherNode)

  • refNode是否包含otherNode节点
  • otherNode是否是refNode的子节点

如果otherNode是refNode的子节点或者是节点本身,返回true,否则返回false

因为当节点相同时,contains也返回true,所以这里还需要处理一下

1
2
3
function contains (refNode, otherNode) {
return refNode.contains(otherNode) && refNode !== otherNode
}

但是这个方法是DOM4级的方法,兼容性不是很好

compareDocumentPosition

语法

refNode.compareDocumentPosition( otherNode )

这个方法返回otherNode节点和refNode节点的位置关系,返回值是一个 位掩码

注意是otherNode相对于refNode的位置

由于返回值是一个 位掩码 ,所以还需要和某一特定值进行&(按位与)运算

那么这某一特定值是什么呢?如下

常量名 十进制值 含义
DOCUMENT_POSITION_DISCONNECTED 1 不在一个文档中
DOCUMENT_POSITION_PRECEDING 2 otherNode在refNode之前
DOCUMENT_POSITION_FOLLOWING 4 otherNode在refNode之后
DOCUMENT_POSITION_CONTAINS 8 otherNode包含refNode
DOCUMENT_POSITION_CONTAINED_BY 16 refNode包含otherNode
DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC 32 待定

这些特定值都是挂在全局变量Node

如果refNode和eotherNode是同一节点,compareDocumentPosition返回0,此时不需要和上面的掩码进行&运算

所以可以有以下代码:

1
2
3
4
5
6
function contains (refNode, otherNode) {
return !!(
refNode.compareDocumentPosition(otherNode)
& Node.DOCUMENT_POSITION_CONTAINED_BY
)
}

总结

综上,我们可以写一个综合的方法来检测是否是子节点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function contains (refNode, otherNode) {
if (!refNode || !otherNode || refNode === otherNode) {
return false
}
// 先检查是否有contains方法
if (refNode.contains && typeof refNode.contains === 'function') {
return refNode.contains(otherNode)
} else if (
// 是否有compareDocumentPosition方法
refNode.compareDocumentPosition
&& typeof refNode.compareDocumentPosition === 'function'
) {
return !!(
refNode.compareDocumentPosition(otherNode)
& Node.DOCUMENT_POSITION_CONTAINED_BY
)
} else {
// DOM结构向上遍历
let parentNode = otherNode.parentNode
while (parentNode !== null) {
if (parentNode === refNode) {
return true
} else {
parentNode = parentNode.parentNode
}
}
return false
}
}

以上

坚持原创技术分享,您的支持将鼓励我继续创作!