DOM2 Traversal and Range 模块定义了两个类型用于辅助顺序遍历 DOM 结构。这两个类型—— NodeIterator 和 TreeWalker——从某个起点开始执行对 DOM 结构的深度优先遍历。 如前所述,DOM 遍历是对 DOM 结构的深度优先遍历,至少允许朝两个方向移动(取决于类型)。 遍历以给定节点为根,不能在 DOM 中向上超越这个根节点。来看下面的 HTML:
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
</head>
<body>
<p><b>Hello</b> world!</p>
</body>
</html>
其中的任何节点都可以成为遍历的根节点。比如,假设以元素作为遍历的根节点,那么接 下来是
元素、元素和两个文本节点(都是元素的后代)。但这个遍历不会到达元 素、元素,或者其他不属于元素子树的元素。而以 document 为根节点的遍历,则可以 访问到文档中的所有节点。图 16-6 展示了以 document 为根节点的深度优先遍历。
从 document 开始,然后循序移动,第一个节点是 document,最后一个节点是包含" world!"的 文本节点。到达文档末尾最后那个文本节点后,遍历会在 DOM 树中反向回溯。此时,第一个访问的节 点就是包含" world!"的文本节点,而最后一个是 document 节点本身。NodeIterator 和 TreeWalker 都以这种方式进行遍历。NodeIteratorNodeIterator 类型是两个类型中比较简单的,可以通过 document.createNodeIterator()方 法创建其实例。这个方法接收以下 4 个参数。
root,作为遍历根节点的节点。
whatToShow,数值代码,表示应该访问哪些节点。
filter,NodeFilter 对象或函数,表示是否接收或跳过特定节点。
entityReferenceExpansion,布尔值,表示是否扩展实体引用。这个参数在 HTML 文档中没
有效果,因为实体引用永远不扩展。
whatToShow 参数是一个位掩码,通过应用一个或多个过滤器来指定访问哪些节点。这个参数对应
的常量是在 NodeFilter 类型中定义的。
NodeFilter.SHOW_ALL,所有节点。
NodeFilter.SHOW_ELEMENT,元素节点。
NodeFilter.SHOW_ATTRIBUTE,属性节点。由于 DOM 的结构,因此实际上用不上。
NodeFilter.SHOW_TEXT,文本节点。
NodeFilter.SHOW_CDATA_SECTION,CData 区块节点。不是在 HTML 页面中使用的。
NodeFilter.SHOW_ENTITY_REFERENCE,实体引用节点。不是在 HTML 页面中使用的。
NodeFilter.SHOW_ENTITY,实体节点。不是在 HTML 页面中使用的。
NodeFilter.SHOW_PROCESSING_INSTRUCTION,处理指令节点。不是在 HTML 页面中使用的。 NodeFilter.SHOW_COMMENT,注释节点。
NodeFilter.SHOW_DOCUMENT,文档节点。
NodeFilter.SHOW_DOCUMENT_TYPE,文档类型节点。
NodeFilter.SHOW_DOCUMENT_FRAGMENT,文档片段节点。不是在 HTML 页面中使用的。
NodeFilter.SHOW_NOTATION,记号节点。不是在 HTML 页面中使用的。
这些值除了 NodeFilter.SHOW_ALL 之外,都可以组合使用。比如,可以像下面这样使用按位或
操作组合多个选项:
let whatToShow = NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT;
createNodeIterator()方法的 filter 参数可以用来指定自定义 NodeFilter 对象,或者一个 作为节点过滤器的函数。NodeFilter 对象只有一个方法 acceptNode(),如果给定节点应该访问就返 回 NodeFilter.FILTER_ACCEPT,否则返回 NodeFilter.FILTER_SKIP。因为 NodeFilter 是一个 抽象类型,所以不可能创建它的实例。只要创建一个包含 acceptNode()的对象,然后把它传给 createNodeIterator()就可以了。以下代码定义了只接收元素的节点过滤器对象:let filter = {
acceptNode(node) {
return node.tagName.toLowerCase() == "p" ?
} };
NodeFilter.FILTER_ACCEPT :
NodeFilter.FILTER_SKIP;
let iterator = document.createNodeIterator(root, NodeFilter.SHOW_ELEMENT, filter, false);
filter 参数还可以是一个函数,与 acceptNode()的形式一样,如下面的例子所示:
let filter = function(node) {
return node.tagName.toLowerCase() == "p" ?
NodeFilter.FILTER_ACCEPT :
NodeFilter.FILTER_SKIP;
};
let iterator = document.createNodeIterator(root, NodeFilter.SHOW_ELEMENT, filter, false);