“DOM2级遍历和范围”模块定义了两个用于辅助完成顺序遍历DOM结构的类型:NodeIterator和TreeWalker。这两个类型能够基于给定的起点对DOM结构执行深度优先遍历。
DOM遍历是深度优先的DOM结构遍历,也就是说,移动的方向至少有两个。遍历以给定的节点为根,不可能向上超出DOM树的根节点。下面我们通过一个例子来了解一下:
任何节点都可以作为遍历的根节点。假设我们现在要以body元素作为根节点,那么遍历的第一步就是访问p元素,然后在访问同为body元素后代的两个文本节点。不过,这次遍历永远不会到达html,head元素。
简单了解之后,我们现在来了解遍历的两种方法。
NodeIterator
我们可以使用document.creatNodeIterator()方法来创建它的新实例。这个方法接受四个参数:
- root:想要做为搜索起点的树中的节点。
- whatToShow:表示要访问哪些节点的数字代码。
- filter:表示应该接受还是拒绝某种特定节点的函数。
- entrtyReferenceExpansion:布尔值,表示是否要扩展实体引用。
我们可以通过creatNodeIterator()方法的filter参数来指定自定义的NodeFilter对象,或者指定一个功能类似节点过滤器的函数。每个NodeFilter对象只有一个方法,即acceptNode();如果应该访问给定的节点,该方法返回NodeFilter.FITER_ACCEPT,如果不应该访问,则返回 NodeFilter.FITER_SKIP或者NodeFilter.FITER_REJECT。下面我们通过一个例子来简单了解一下,这段代码展示了如何创建一个只显示p元素的节点迭代器。
var fiter = function(node){
return node.tagName.toLowerCase() === 'p'?
NodeFilter.FITER_ACCEPT: NodeFilter.FITER_SKIP
};
var iterator = document.creatNodeIterator(root,NodeFilter.SHOW_ELEMENT,filter,false);
如果不指定过滤器,那么应该在第三个参数的位置传入null。通过下面的代码我们就可以访问所有类型节点。
var iterator = document.creatNodeIterator(root,NodeFilter.SHOW_ALL,null,false);
NodeIterator类型的两个主要方法是nextNode()和previousNode()。
- nextNode():用于向前前进一步。第一次调用nextNode()会返回根节点。当遍历到最后一个节点时,nextNode()返回null。
previousNode():用于向后后退一步。当遍历到最后一个节点,且previousNode()返回根节点之后,再次调用就返回null。
下面我们就通过一下例子来演示一下:
<div id="div1">
<p><b>Mr.</b>张</p>
<ul>
<li>List item 1</li>
<li>List item 2</li>
<li>List item 3</li>
</ul>
</div>
如果现在我们想遍历li元素,我们就可以像这样:
var oDiv = document.getElementById('div1');
var filter = function (node) {
return node.tagName.toLowerCase() === 'li' ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
};
var iterator = document.createNodeIterator(oDiv,NodeFilter.SHOW_ELEMENT,filter,false);
var node = iterator.nextNode();
while (node !== null){
console.log(node.tagName.toLowerCase());
node = iterator.nextNode();
}
TreeWalker
TreeWalker是NodeIterator的一个更高级的版本。除了nextNode()和previousNode()方法外,这个类型还提供了下列的方法:
- parentNode():遍历到当前节点的父节点。
- firstChild():遍历到当前节点的第一个子节点。
- lastChild():遍历到当前节点的最后一个子节点。
- nextSibling():遍历到当前节点的下一个同辈节点。
previousSibling():遍历到当前节点的上一个同辈节点。
创建TreeWalker对象使用document.creatTreeWalker()方法,这个方法接受的四个参数和document.creatNodeIterator()方法相同。
下面来看一下使用该方法来实现上面的例子:
var oDiv = document.getElementById('div1');
var filter = function (node) {
return node.tagName.toLowerCase() === 'li' ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
};
var iterator = document.createTreeWalker(oDiv,NodeFilter.SHOW_ELEMENT,filter,false);
var node = iterator.nextNode();
while (node !== null){
console.log(node.tagName.toLowerCase());
node = iterator.nextNode();
}
在这里,filter可以返回的值不同。除了NodeFilter.FILTER_ACCEPT :和NodeFilter.FILTER_SKIP,还可以使用NodeFilter.FILTER_REJECT。在使用NodeIterator对象时,NodeFilter.FILTER_SKIP和NodeFilter.FILTER_REJECT的作用相同:跳过指定的节点。但在使用TreeWalker对象时,NodeFilter.FILTER_SKIP会跳过指定的节点继续前进到子树的下一个节点,但NodeFilter.FILTER_REJECT会跳过相应节点及该节点的整个子树。例如前面的例子,如果我们将NodeFilter.FILTER_SKIP修改为NodeFilter.FILTER_REJECT,结果就是不会访问任何节点。因为第一个返回的节点是div,它的标签名不是li,于是就会返回NodeFilter.FILTER_REJECT,这样就会跳过整个子树。因为div是遍历的根节点,所以结果就会停止遍历。
当然,TreeWalker真正强大的地方在于能够在DOM结构中沿任何方向移动。这就需要使用到前面说到的它比NodeIterator多的方法了。具体的使用我就不一一说明了。
今天的学习分享就到这里啦,图书馆好热呀!买瓶饮料犒劳一下自己嘻嘻嘻~~
关于所写内容如果有什么问题和疑惑希望大家可以告诉我奥,我们大家一起进步~~