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();
}
}

欢迎小伙伴评论交流~~

先序遍历DOM树的5种方法的更多相关文章

  1. JavaScript 算法应用: 遍历DOM树的两种方式

    1 常见的DOM树结构: 2  DOM数遍历有两种方式: 3 广度优先代码: 4 深度优先遍历代码

  2. 函数遍历DOM树

    //获取页面中的根节点--根标签   var root=document.documentElement;//html   //函数遍历DOM树   //根据根节点,调用fn的函数,显示的是根节点的名 ...

  3. jQuery向上遍历DOM树之parents(),parent(),closest()之间的区别

    http://www.poluoluo.com/jzxy/201312/253059.html 在这个sprint中,因为要写前端UI,所以用到了jQuery,但是jQuery在向上遍历DOM树的AP ...

  4. 拷贝和遍历DOM树

    一.浅拷贝: 拷贝就是复制,就相当于把一个对象中的所有内容,复制一份给另一个对象,直接复制, 或者说,就是把一个对象的地址给了另外一个对象,他们的指向相同,两个对象之间有相同的属性或者方法,都可以使用 ...

  5. JS高级---遍历DOM树

    遍历DOM树  第一个函数: 给我根节点, 我会找到所有的子节点: forDOM(根节点)  获取这个根节点的子节点  var children=根节点的.children  调用第二个函数  第二个 ...

  6. Jquery遍历筛选数组的几种方法和遍历解析json对象|Map()方法详解

    Jquery遍历筛选数组的几种方法和遍历解析json对象|Map()方法详解 一.Jquery遍历筛选数组 1.jquery grep()筛选遍历数组 $().ready( function(){ v ...

  7. JQuery遍历json数组的3种方法

    这篇文章主要介绍了JQuery遍历json数组的3种方法,本文分别给出了使用each.for遍历json的方法,其中for又分成两种形式,需要的朋友可以参考下 一.使用each遍历 $(functio ...

  8. Java遍历List集合的三种方法

    Java遍历List集合的三种方法 List<String> list = new ArrayList<String>(); list.add("aaa") ...

  9. (转载)Java中如何遍历Map对象的4种方法

    在Java中如何遍历Map对象 How to Iterate Over a Map in Java 在java中遍历Map有不少的方法.我们看一下最常用的方法及其优缺点. 既然java中的所有map都 ...

随机推荐

  1. 处理ajax数据;数据渲染

    当我们用ajax把数据拿到前台,该如何渲染到页面,有以下几种方式: 一:使用字符串拼接的方法 声明一个空变量,然后拼接 var st=""; st+="<div&g ...

  2. 使用PHP实现手机端APP支付宝的支付功能

    最近应业务需求,做了支付宝支付和微信支付,今天分享一下手机端app支付宝支付对接流程,实际开发过程是前后端分离,前端调用后端API接口,实现功能返回数据,我所用的跨挤啊为TP5,大致可以分为四步: 1 ...

  3. Ubuntu 18.04 下如何配置mysql 及 配置远程连接

    首先是大家都知道的老三套,啥也不说上来就放三个大招: sudo apt-get install mysql-server sudo apt isntall mysql-client sudo apt ...

  4. 201621123002《Java程序设计》第十周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常相关内容. 2. 书面作业 本次PTA作业题集异常 1. 常用异常 结合题集题目7-1回答 1.1 自己以前编写的代码中经常出现 ...

  5. 将IP转换为16进制,用于IPv4-IPv6

    # --*-- coding: utf-8 --*--# create by xiaocaiji while 1: str_ip = input("input a IP:") li ...

  6. CSS绝对定位的原点:是在border上、padding上还是在content上?

    用了那么久的绝对定位,却一直没在意一个问题,就是绝对定位的原点,究竟是在盒模型的哪一处.今天想到这个问题,直接搜索没有找到标准文档,也没有搜索到相关的问题,于是决定自己动手实现一下看看,并把这个结果发 ...

  7. Sql Server免域,异地备份

    --先决条件 开启xp_cmdshellEXEC sp_configure 'show advanced options', 1;RECONFIGURE;EXEC sp_configure 'xp_c ...

  8. 笔记本电脑连接wifi,同时提供热点wifi给手机使用

    笔记本电脑连接wifi,同时提供热点wifi给手机使用 用电脑建立WiFi供手机平板设备使用ps:电脑需要有无线网卡,一般笔记本都自带 此教程仅适用Windows 7 & 8,1.打开笔记本的 ...

  9. 【Python】【BugList12】python自带IDLE执行print(req.text)报错:UnicodeEncodeError: 'UCS-2' codec can't encode characters in position 93204-93204

    [代码] # -*- coding:UTF-8 -*- import requests if __name__ == '__main__': target = 'https://unsplash.co ...

  10. 重写toFixed()方法

    1.直接在原型上修改,仍然使用元调用方式 Number.prototype.toFixed = function (exponent) { return parseInt(this * Math.po ...