视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
javascript先序遍历DOM树的方法
2020-11-27 20:25:42 责编:小采
文档

DOM树由文档中的所有节点(元素节点、文本节点、注释节点等)所构成的一个树结构,DOM树的解析和构建是浏览器要实现的关键功能。既然DOM树是一个树结构,那么我们就可以使用遍历树结构的相关方法来对DOM树进行遍历,同时DOM2中的"Traversal"模块又提供了两种新的类型,从而可以很方便地实现DOM树的先序遍历。

注:本文中的5种方法都是对DOM的先序遍历方法(深度优先遍历),并且只关注Element类型。

1. 使用DOM1中的基础接口,递归遍历DOM树

DOM1中为基础类型Node提供了一些api,通过这些api可以完成一些基础的DOM操作。使用递归遍历DOM树的代码比较简单,核心思想就是先处理当前节点,然后再从左到右递归遍历子节点,代码如下:

/**
 * 使用递归的方式先序遍历DOM树
 * @param node 根节点
 */
 function traversal(node){
 //对node的处理
 if(node && node.nodeType === 1){
 console.log(node.tagName);
 }
 var i = 0, childNodes = node.childNodes,item;
 for(; i < childNodes.length ; i++){
 item = childNodes[i];
 if(item.nodeType === 1){
 //递归先序遍历子节点
 traversal(item);
 }
 }
 }

2. 使用DOM1的基础接口,迭代遍历DOM树

与第1种方法不同,这一次使用迭代的方法遍历DOM树。使用迭代遍历DOM树相对复杂一些,关键点在于使用一个栈来维护节点的访问路径,当处理完当前节点时,先把该节点的第一个Element子节点作为下一次循环的根节点,并且按照从右到左的顺序,将当前节点的其他子元素节点压入栈中。如果当前节点没有一个Element子节点,则从栈中弹出一个Element节点作为下一次循环的根节点,直到取不到根节点为止。代码如下:

/**
 * 使用迭代的方式先序遍历DOM树
 * @param node 根节点
 */
function traversalIteration(node){
 var array = [], i = 0,k = 0,elementCount = 0, len = 0, childNodes,item;
 while(node != null){
 console.log(node.tagName);
 childNodes = node.childNodes;
 len = node.childNodes.length;
 elementCount = 0;
 if(len > 0){
 for(i = 0; i < len; i++){
 item = childNodes[i];
 if(item.nodeType === 1){
 elementCount++;
 node = item;
 break;
 }
 }
 for(k = len -1 ; k > i; k--){
 item = childNodes[k];
 if(item.nodeType == 1){
 elementCount++;
 array.push(item);
 }
 }
 if(elementCount < 1){
 node = array.pop();
 }
 }else{
 node = array.pop();
 }
 }
}

3. 使用DOM扩展的Element Traversal API,递归遍历DOM树

DOMElement Traversal API提供了几个方便DOM遍历的接口,从而可以更加方便地取得一个节点的Element子节点。在《DOM扩展:DOM API的进一步增强[总结篇-上]》的第2节介绍了DOM扩展的Element Traversal API。代码如下:

/**
 * 使用DOM扩展的Traversal API提供的新的接口先序遍历DOM树
 * @param node 根节点
 */
function traversalUsingTraversalAPI(node){
 if(node && node.nodeType === 1){
 console.log(node.tagName);
 }
 var i = 0,len = node.childElementCount, child = node.firstElementChild;
 for(; i < len ; i++){
 traversalUsingTraversalAPI(child);
 child = child.nextElementSibling;
 }
}

4. 使用NodeIterator

DOM2的"Traversal"模块提供了NodeIterator类型,使用它可以很方便地实现DOM树的先序遍历,《JavaScript高级程序设计第三版》的12.3.1节介绍了这个类型,我们这里直接给出代码如下:

/**
 * 使用DOM2的"Traversal"模块提供的NodeIterator先序遍历DOM树
 * @param node 根节点
 */
function traversalUsingNodeIterator(node){
 var iterator = document.createNodeIterator(node, NodeFilter.SHOW_ELEMENT,null,false);
 var node = iterator.nextNode();
 while(node != null){
 console.log(node.tagName);
 node = iterator.nextNode();
 }
}

5. 使用TreeWalker

TreeWalker类型可以说是NodeIterator类型的增强版,《JavaScript高级程序设计第三版》的12.3.2节介绍了这个类型,我们这里也直接给出代码如下:

/**
 * 使用DOM2的"Traversal"模块提供的TreeWalker先序遍历DOM树
 * @param node 根节点
 */
function traversalUsingTreeWalker(node){
 var treeWalker = document.createTreeWalker(node, NodeFilter.SHOW_ELEMENT,null,false);
 if(node && node.nodeType === 1){
 console.log(node.tagName);
 }
 var node = treeWalker.nextNode();
 while(node != null){
 console.log(node.tagName);
 node = treeWalker.nextNode();
 }
}

下载本文
显示全文
专题