JS高级程序设计阅读笔记---DOM遍历

简介

“DOM2 级遍历和范围”模块定义了两个用于辅助完成顺序遍历 DOM 结构的类型:NodeIterator和 TreeWalker。

NodeIterator

NodeIterator类型是两者中比较简单的一个,可以使用 document.createNodeIterator()方法创建它的新实例。这个方法接受下列 4 个参数。

  • root:想要作为搜索起点的树中的节点。
  • whatToShow:表示要访问哪些节点的数字代码。
  • filter:是一个 NodeFilter 对象,或者一个表示应该接受还是拒绝某种特定节点的函数。
  • entityReferenceExpansion:布尔值,表示是否要扩展实体引用。这个参数在 HTML 页面中没有用,因为其中的实体引用不能扩展。

whatToShow参数是一个位掩码,通过应用一或多个过滤器(filter)来确定要访问哪些节点。这个参数的值以常量形式在 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_ENTITYE:显示实体节点。对 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 之外,可以使用按位或操作符来组合多个选项,如下面的例子所示:

var whatToShow = NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT; 

可以通过 createNodeIterator()方法的filter 参数来指定自定义的 NodeFilter 对象,或者指定一个功能类似节点过滤器(node filter)的函数。每个 NodeFilter 对象只有一个方法,即 acceptNode()
如果应该访问给定的节点,该方法返回NodeFilter.FILTER_ACCEPT,如果不应该访问给定的节点,该方法返回 NodeFilter.FILTER_SKIP。由于 NodeFilter 是一个抽象的类型,因此不能直接创建它的实例。在必要时,只要创建一个包含 acceptNode()方法的对象,然后将这个对象传入createNodeIterator()中即可。

下列代码展示了如何创建一个只显示<p>元素的节点迭代器。

//第一种
const filter = {
 acceptNode: function(node){
 	return node.tagName.toLowerCase() == "p" ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
 }
}; 
//第二种=========filter也可以是一个类型acceptnode的函数
const filter = function(node){
  return node.tagName.toLowerCase() == "p" ?NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
}; 
const  iterator = document.createNodeIterator(root, NodeFilter.SHOW_ELEMENT,filter, false); 

一般来说大家都是用第二种,因为第二种比较简单,更符合其他代码。需要主要的是,如果不指定过滤器,那么应该在第三个参数的位置上传入 null。

NodeIterator 类型的两个主要方法是 nextNode()和 previousNode()。顾名思义,在深度优先的 DOM 子树遍历中,nextNode()方法用于向前前进一步,而 previousNode()用于向后后退一步。在刚刚创建的 NodeIterator 对象中,有一个内部指针指向根节点,因此第一次调用 nextNode()会返回根节点。当遍历到 DOM 子树的最后一个节点时,nextNode()返回 null。previousNode()方法
的工作机制类似。当遍历到 DOM 子树的最后一个节点,且 previousNode()返回根节点之后,再次调用它就会返回 null。

以下列HTML为例

<div id="div1">
	 <p><b>Hello</b> world!</p>
	 <ul>
		 <li>List item 1</li>
		 <li>List item 2</li>
		 <li>List item 3</li>
	 </ul>
</div>

假设我们想要遍历

元素中的所有元素,那么可以使用下列代码。

const div = document.getElementById("div1");
const iterator = document.createNodeIterator(div, NodeFilter.SHOW_ELEMENT,null, false);
let node = iterator.nextNode();
while (node !== null) {
 console.log(node.tagName); //输出标签名
 node = iterator.nextNode();
} 

在这里插入图片描述

TreeWalker

TreeWalkerNodeIterator 的一个更高级的版本。除了包括 nextNode()和 previousNode()在内的相同的功能之外,这个类型还提供了下列用于在不同方向上遍历 DOM 结构的方法。

  • parentNode():遍历到当前节点的父节点;
  • firstChild():遍历到当前节点的第一个子节点;
  • lastChild():遍历到当前节点的最后一个子节点;
  • nextSibling():遍历到当前节点的下一个同辈节点;
  • previousSibling():遍历到当前节点的上一个同辈节点

NodeIterator不同的有两点:

  • 遍历不会包括起点节点
    在这里插入图片描述
    可以看出是没有起点div节点的。
  • filter 可以返回的值有所不同。除了 NodeFilter.FILTER_ACCEPTNodeFilter.FILTER_SKIP 之外,还可以使用 NodeFilter.FILTER_REJECTNodeFilter.FILTER_SKIP跳过指定节点,继续遍历,而NodeFilter.FILTER_REJECT则是直接结束。

当然,TreeWalker真正强大的地方在于能够在 DOM 结构中沿任何方向移动。使用 TreeWalker遍历 DOM 树,即使不定义过滤器,也可以取得所有<li>元素,如下面的代码所示。

const div = document.getElementById("div1")
const walker = document.createTreeWalker(div,NodeFilter.SHOW_ELEMENT,null,false)
walker.firstChild(); //转到<p> 
walker.nextSibling(); //转到<ul> 
let node = walker.firstChild(); //转到第一个<li>
while(node!==null){
    console.log(node.tagName);
    node = walker.nextSibling()
}

TreeWalker 类型还有一个属性,名叫 currentNode,表示任何遍历方法在上一次遍历中返回的节点。通过设置这个属性也可以修改遍历继续进行的起点,如下面的例子所示。

let node = walker.nextNode();
alert(node === walker.currentNode); //true
walker.currentNode = document.body; //修改起点
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值