Skip to content

DOM 深度优先遍历

深度优先遍历

下面 DOM 遍历顺序如下

html
<html>
    <head>
        <title>Example</title>
    </head>
    <body>
        <p><b>hello</b> world!</p>
    </body>
</html>

NodeIterator

1. 创建实例

通过 document.createNodeIterator(root, whatToShow, filter, entityReferenceExpansion) 创建实例

参数说明
root作为遍历根节点的节点
whatToShow数值,表示应该访问哪些节点
filterNodeFilter 对象或函数,表示是否接受或跳过特定节点
entityReferenceExpansion布尔值,表示是否扩展实体引用。没什么用
2. whatToShow 详解

whatToShow 是一个位掩码,可以决定访问哪些类型的节点,以下是常用的几个值

说明
NodeFilter.SHOW_ALL显示所有类型的节点
NodeFilter.SHOW_ELEMENT显示元素节点
NodeFilter.SHOW_TEXT显示文本节点
NodeFilter.SHOW_COMMENT显示注释节点
NodeFilter.SHOW_DOCUMENT显示文档节点

这些值除了 NodeFilter.SHOW_ALL 外,可以组合使用

js
NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT
3. filter 详解

可以自定义过滤函数,返回 NodeFilter.FILTER_ACCEPT 表示访问此节点,返回 NodeFilter.FILTER_SKIP 表示不访问此节点

js
const filter = node => node.tagName.toLowerCase() === 'p' ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP
4. 遍历方法
  • nextNode():以深度优先方式前进一步。第一次调用,返回根节点
  • previousNode():以深度优先方式后退一步
js
// 可以如下遍历
const body = document.body
const filter = node => node.tagName.toLowerCase() === 'p' ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP

const iterator = document.createNodeIterator(body, NodeFilter.SHOW_ELEMENT, filter, false)
let node = iterator.nextNode()

while (node !== null) {
    // ...
    node = iterator.nextNode()
}

TreeWalker

TreeWalkerNodeIterator 的高级版,和 NodeIterator 一样

1. 创建实例

通过 document.createTreeWalker(root, whatToShow, filter, entityReferenceExpansion) 创建实例

2. 更多遍历方法

在其上添加更多的遍历方法

方法说明
parentNode()遍历到当前节点的父节点
firstChild()遍历到当前节点的第一个子节点
lastChild()遍历到当前节点的最后一个子节点
nextSibling()遍历到当前节点的下一个兄弟节点
previousSibling()遍历到当前节点的上一个兄弟节点

这样可以更自由的进行遍历

3. 节点过滤器(filter)多了一个返回值
  • NodeFilter.FILTER_REJECT:表示跳过该节点以及该节点的整个子树
4. 读写当前节点
  • 可以通过属性 currentNode访问当前正在遍历的那一个节点
  • 可以改写此属性,以改变遍历的指针