"DOM2 级遍历和范围"模块定义了两个方法用于辅助完成顺序遍历 DOM 结构的类型: NodeIterator 和 TreeWalker 。这两个类型可以基于给定的起点对 DOM 结构执行深度优先(depth-first)的遍历操做。javascript
任何节点均可以做为遍历的根节点。引用《JavaScript高级程序设计(第3版)》的插图,表示以 document 对象为根节点:
html
使用document.createNodeIterator(rootNode, whatToShow, filter, isEntrityReferenceExpansion?)
方法能够建立 NodeIterator 的实例。 4 个参数的意思:
java
// node 为每次遍历的节点对象
function acceptNode(node) {
// 过滤除了 div 之外的元素
return node.nodeName.toLowerCase() === 'div'
? NodeFilter.FILTER_ACCEPT
: NodeFilter.FILTER_SKIP
}复制代码
函数createNodeIterator()
执行后,返回一个 NodeIterator 的实例,该对象主要有两个方法:node
null
。null
。完整实例以下:函数
<body> <div class="div1">div1</div> <div class="div2"> <p>pppppp</p> text </div> </body>复制代码
// 过滤的类型选择
let whatToShow = NodeFilter.SHOW_ALL;
// 过滤器(传入函数)
let filter = function (node) {
return node.nodeName.toLowerCase() === 'div' ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP
}
// 过滤器2(传入对象)
let filter2 = {
acceptNode: filter
}
// 建立迭代器
let iterator = document.createNodeIterator(document.body, whatToShow, filter, false);
// 测试
console.log(iterator.nextNode()); // "<div class="div1">div1</div>"
console.log(iterator.previousNode()); // "<div class="div2">...</div>"
console.log(iterator.nextNode()); // "<div class="div1">div1</div>"
console.log(iterator.nextNode()); // null
复制代码
使用document.createTreeWalker()
方法能够建立 TreeWalker 对象,参数与createNodeIterator()
方法一致。TreeWalker 是 NodeIterator 的一个高级版本,使用方法也基本一致,有一点除外,过滤函数的返回值若是是 "NodeFilter.FILTER_REJECT" ,该节点的子节点都会被跳过。除了包含 nextNode() 和 previousNode() 方法以外,还提供了以下属性/方法:
测试
<body> <div id="div1"> div1 <div id="div1_1"> div1.1</div> <div id="div1_2"> div1.2</div> </div> <div id="div2"> div2 <p> div2-p</p> </div> </body>复制代码
let filter = function (node) {
return node.nodeName.toLowerCase() === 'div' ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP
}
let walker = document.createTreeWalker(document.body, NodeFilter.SHOW_ALL, filter, false)
// 测试
console.log(walker.nextNode()); // "<div id="div1">...</div>"
console.log(walker.nextSibling()); // "<div id="div2">...</div>"
console.log(walker.previousSibling()); // "<div id="div1">...</div>"
console.log(walker.firstChild()); // "<div id="div1_1">...</div>"
console.log(walker.parentNode()); // "<div id="div1">...</div>"
console.log(walker.lastChild()); // "<div id="div1_2">...</div>"
console.log(walker.nextNode()); // "<div id="div2">...</div>"复制代码
须要注意的是,"walker" 只能在 TreeWalker 对象内"游走",上面几个方法也是针对已过滤的结果的相对位置"游走",即便"div"内有"Text"类型的节点。除非建立 TreeWalker 对象的第一第二个参数分别传入 document 和 null ,就能够在 DOM 树内随意"游走"。
ui
"DOM2 级遍历和范围"模块定义"范围"(range)接口。经过范围能够选择文档中的一个区域,而没必要考虑节点的界限。使用document.createRange()
方法能够建立 range 对象。
spa
Range 对象的属性提供了当前范围在文档中的位置信息。
设计
<p>hello</p>
中被选择了"llo",本属性值为 3 ;不然,表示起点节点在父节点的 childNodes 是第几个,即经过range.startContainer.childNodes[range.startOffset - 1]
可访问起点节点。如下方法均用于修改 Range 对象的范围,无返回值。
code
<p>hello</p>
选择了"llo</p>"时,会自动将其补全,即起点节点为<p>llo</p>
。能够当作快速设置指定属性。使用如下方法,能够对 DOM 删除或插入。
<p>hello</p>
被删除了"llo</p>",则剩下的节点会变成<p>he</p>
,仍是完整的节点。<div>hello <b>world</b></div>
的 HTML 文档片断,范围选择"llo <b>world</b>
",使用document.createElement('p')
建立一个用于环绕的 node 节点对象,而后使用本方法,原 HTML 文档片断将变为<div>he<p>llo <b>world</b></p></div>
。须要注意的是,在使用本方法前,对 "node" 对象插入其余节点是不会有效果的;但为 "node" 对象添加特性是有效果的。本方法执行时,后台会执行以下步骤:<p id="p1">p1</p><p id="p2">p2</p>
,分别获取"p1"、"p2"节点对象,建立range对象设定起点终点range.setStartAfter(p1); range.setEndBefore(p2)
,由于"p1"和"p2"是相邻节点,因此range.collapsed
的值为true
。 cloneContents()
方法区分。deleteContents()
方法仍然会删除 DOM。)