JavaScript DOM文档遍历实战
创始人
2024-07-13 17:21:56
0

在介绍了《JavaScript DOM修改文档树方法实例》与《JavaScript DOM实战:创建和克隆元素》,本文将介绍JavaScript DOM文档遍历的详细知识,我们先从HTML页面最基本的组成元素讨论起:

  1.   

访问元素,你应该明白它是该文件的document元素,那你就可以使用document的documentElement属性:

  1. var oHtml=document.documentElement;//可以直接访问元素  
  2. alert("节点名称 : "+oHtml.nodeName);//节点名称  
  3. alert("节点类型 : "+oHtml.nodeType);//节点类型为 1  

获取 和 元素:

  1. var oHead=oHtml.firstChild;//HEAD节点  
  2. var oBody=oHtml.lastChild;//BODY节点  

也可以通过childNodes属性,获取 和 元素:

  1. var oHead=oHtml.childNodes.item(0);//HEAD节点  
  2. //var oHead=oHtml.childNodes[0];//简写,也有同样的结果是HEAD节点  
  3. var oBody=oHtml.childNodes.item(1);//BODY节点  
  4. //var oBody=oHtml.childNodes.item(1);//简写,也有同样的结果是BODY节点  

注意:方括号标记其实是NodeList在javascript中的简便实现。实际上正式的从childNodes列表中获取子节点的方法是使用item()方法:HTML DOM 中的专有属性 document.body ,它常用于直接访问元素:

  1. var oBody=document.body;  

既然我们都知道了以上节点对象的获取方式,那我们用oHtml,oHead,oBody 这三个变量来确定一下它们之间的关系:

  1. alert(oHead.parentNode==oHtml);//HEAD节点的父节点是BODY节点,返回 true   
  2. alert(oBody.parentNode==oHtml);//BODY节点的父节点是BODY节点,返回 true   
  3. alert(oBody.previousSibling==oHead);//BODY节点的上一个兄弟节点是HEAD节点 ,返回 true  
  4. alert(oHead.nextSibling==oBody);//HEAD节点的下一个兄弟节点是BODY节点,返回 true  
  5. alert(oHead.ownerDocument==document); //返回一个节点的根元素(Document),HEAD节点是否指向该文档,返回 true  

通过上面的学习我们已经了解遍历节点的最基本的方式, 也学会了如何找到某一个节点的兄弟节点及它的子节点。

#p#

复杂的节点遍历

在上面的学习中我们好像没有遇到过大的阻碍,下面我们以一个“导航条”为实例:

  1.  
  2.     

    我的导航条

                
  3.      
  4.        
  5. HOME
  6.  
  7.        
  8. (X)Html / Css
  9.  
  10.        
  11. Ajax / RIA
  12.  
  13.        
  14. GoF
  15.  
  16.        
  17. JavaScript
  18.  
  19.        
  20. JavaWeb
  21.  
  22.        
  23. jQuery
  24.  
  25.        
  26. MooTools
  27.  
  28.        
  29. Python
  30.  
  31.        
  32. Resources
  33.  
  34.      
  

首先我想把看一下我的导航条下有多少个子节点。我***想到的是前面我学过的查找元素的2种方法:

getElementById() # 通过ID属性查找元素

该方法将返回一个与那个有着给定id属性值的元素节点相对应的对象。

getElementsByTagName() # 通过标签名称查找元素

该方法返回一个对象数组,每个对象分别对应着文档里有着给定标签的一个元素。

  1.  
  2. /*  
  3. 通过ID属性查找元素 ,用的是文档对象的getElementById()方法,  
  4. 查找到我们想要的元素对象,根据这个节点元素的 childNodes 属性,  
  5. 遍历出所有的子节点对象。  
  6. */  
  7. function queryElementsId(){  
  8.   var elemensArray,nav,nav_list;  
  9.   elemensArray=[];  
  10.   nav=document.getElementById("nav");  
  11.   /*注意IE和FF中处理Text节点上存在着一些差异*/  
  12.      navnav_list=nav.childNodes;  
  13.      for(var i=0;i
  14.     elemensArray[elemensArray.length]=nav_list[i];  
  15.     //elemensArray.push(nav_list[i]); //同上一样的结果  
  16.      }  
  17.   return elemensArray;  
  18.    
  19. }  
  20. /*  
  21. 我们观察到我的导航条是有规律的,是用无序列表元素组成的,只有定位到 <ul>元素  
  22. ;然后把getElementsByTagName()方法可以返回相同元素对象的集合,  
  23. 查用它找一组元素,太方便了。  
  24. */  
  25. function queryElementsTagName(){  
  26.  var elemensArray,nav,nav_list;  
  27.  elemensArray=[];  
  28.  var nav=document.getElementById("nav");  
  29.  var navnav_list=nav.getElementsByTagName("li");//返回相同的一组元素  
  30.  for(var i=0;i
  31.   elemensArray[elemensArray.length]=nav_list[i];  
  32.   //elemensArray.push(nav_list[i]); //同上一样的结果  
  33.  }  
  34.  return elemensArray;  
  35.    
  36. }  
  37.   

节点遍历

那我们接下来,测一下是否是我们想要的东西:

  1.  
  2. window.onload=function(){  
  3.      /****个方法*/  
  4.      var list= queryElementsId();   
  5.   /*第二个方法*/  
  6.  //var list= queryElementsTagName();   
  7.  var s="";  
  8.  for(var i=0;i
  9.   s+=list[i].nodeName+"\n";   
  10.     }  
  11.  alert(s);  
  12.  }  
  13.   

先看一下***个方法queryElementsId()好像我们在IE中没有发现有什么问题,那我们在Firefox中看一下是否也是我们想要的结果。

这时,问题出现了,不同的浏览器在判断何为Text节点上存在着一些差异,例如在A级浏览器中的FF和IE就有很大的差异,FireFox会把元素之间的空白、换行、tab都是Text节点,IE下会把空白全部忽略掉,只有内联元素(如em,span)后的换行、空格、tab会被认为是一个Text。既然遇到了问题那我们就得解决问题,问题的根源我们也知道了,那相应的解决方案就好做了。

方法一:

  1.  
  2. /*  
  3. 《精通javascript》上提供了一个函数,用于处理xm中的这些空格,其作用原理就是找出文本节点,并删除这些节点,以达到删除这些空格的目的。  
  4. */  
  5.    
  6. function cleanWhitespace(element){  
  7.     //如果不提供参数,则处理整个HTML文档  
  8.     elementelement = element || document;  
  9.     //使用***个子节点作为开始指针  
  10.     var cur = element.firstChild;  
  11.    
  12.     //一直到没有子节点为止  
  13.     while (cur != null){  
  14.         //如果节点为文本节点,应且包含空格  
  15.         if ( cur.nodeType == && ! /\S/.test(cur.nodeValue)){  
  16.             //删除这个文本节点  
  17.             element.removeChild( cur );  
  18.    
  19.             //否则,它就是一个元素  
  20.         } else if (cur.nodeType == 1){  
  21.             //递归整个文档  
  22.             cleanWhitespace( cur );  
  23.         }  
  24.    
  25.         curcur = cur.nextSibling;//遍历子节点  
  26.     }  
  27. }  
  28.   

方法二:

  1.  
  2.    
  3. /*  
  4. ***,利用数组写了一个函数,能够有效的处理dom中的空格,其原理就是将一个元素的的父元素找出来,然后通过它父元素的childNodes属性找出该元素的所有兄弟元素。遍历该元素和它的兄弟元素,将所有元素节点放在一个数组里。这样调用这个数组,就只有元素节点而没有文本节点,也就没有了讨厌的空格.  
  5.    
  6. */  
  7.    
  8. function cleanWhitespaces(elem){  
  9.     //如果不提供参数,则处理整个HTML文档  
  10.  var elemelem = elem || document;   
  11.  var parentElem = elem.parentNode; //返回一个节点的父类节点  
  12.  var childElem = parentElem.childNodes; //返回一个节点的子节点的节点列表  
  13.  var childElemArray = new Array;   
  14.  for (var i=0; i
  15.   if (childElem[i].nodeType==1){//把所有节点是元素节点类型的节点存放到数组里  
  16.    childElemArray.push(childElem[i]);   
  17.   }  
  18.  }  
  19.     return childElemArray;   
  20. }   
  21.   

方法三:推荐

  1.  
  2. /*  
  3. 原理是对元素的所有的子节点做一个遍历。然后做一个判断,如果是子元素节点(nodeType = 1),则遍历该子元素的所有的子节点,用递归检查是否包含空白节点;如果处理的子节点是文本节点(nodeType = 3),则检查是否是纯粹的空白节点,如果是,就将它从xml对象中删除。  
  4. */  
  5. function removeWhitespace(xml){  
  6.     var loopIndex;  
  7.    
  8.     for (loopIndex = 0; loopIndex < xml.childNodes.length; loopIndex++){  
  9.         var currentNode = xml.childNodes[loopIndex];  
  10.         if (currentNode.nodeType == 1){  
  11.             removeWhitespace(currentNode);  
  12.         }  
  13.    
  14.         if (((/^\s+$/.test(currentNode.nodeValue))) &&(currentNode.nodeType == 3)){  
  15.             xml.removeChild(xml.childNodes[loopIndex--]);  
  16.         }  
  17.     }  
  18. }  
  19.   

好了,我们在验证一下,#Text节点问题是否处理掉了。那我们就用方法3 中removeWhitespace(nav)方法来处理queryElementsId()方法中的#Text节点问题。

  1.  
  2. function queryElementsId(){  
  3.   var elemensArray,nav,nav_list;  
  4.   elemensArray=[];  
  5.   nav=document.getElementById("nav");  
  6.   /*处理#Text节点问题*/  
  7.   removeWhitespace(nav);  
  8.    
  9.   /*注意IE和FF中处理Text节点上存在着一些差异*/  
  10.      navnav_list=nav.childNodes;  
  11.      for(var i=0;i
  12.     elemensArray[elemensArray.length]=nav_list[i];  
  13.     //elemensArray.push(nav_list[i]); //同上一样的结果  
  14.      }  
  15.   return elemensArray;  
  16.    
  17. }  
  18.   

正如看到的结果,IE和FireFox中都没有问题了。

#p#

一个比较通用的方法:

  1.  
  2. function text(elem){  
  3.  var t="";  
  4.  //如果传入的是元素,则继续遍历其子元素  
  5.  //否则假定它是一个数组  
  6.  elemelem=elem.childNodes || elem;  
  7.  //遍历所有子节点  
  8.  for(var i=0; i
  9.      //如果不是元素,追加其文本值  
  10.   //否则,递归遍历所有元素的子节点  
  11.   t+=elem[i].nodeType !=1?elem[i].nodeValue:text(elem[i].childNodes);  
  12.    
  13.  }  
  14.     //返回比配的文本  
  15.     return t;  
  16. }  
  17.  

用元素节点的DOM属性遍历DOM树

  1.  
  2. window.onload=function(){  
  3.   /*定位想要的节点*/  
  4.   var nav=document.getElementById("nav");  
  5.   /*查找父节点*/  
  6.   var p_n=nav.parentNode;  
  7.   alert("父节点的元素名称:"+p_n.nodeName);  
  8.    
  9.   /*处理FF遍历节点中的#Text */  
  10.   removeWhitespace(nav);//移除所有的空Text节点  
  11.    
  12.   /*查找子节点*/    
  13.   var c_n_f=nav.firstChild;//***个节点对象  
  14.   //var c_n_f=nav.childNodes[0];//同上一样的结果  
  15.   var c_n_l=nav.lastChild;//***一个节点对象  
  16.   //var c_n_l=nav.childNodes[nav.childNodes.length-1];//同上一样的结果  
  17.   alert("***个节点:"+c_n_f.nodeName+"  "+"***一个节点 :"+c_n_l.nodeName);   
  18.   /*查找兄弟节点 或叫 相邻节点 */  
  19.   /*用nextSibling和PreviousSibling必须有一个参考点,这样指针才知道自己往那里移动*/  
  20.   var c_n_s=c_n_f.nextSibling;//***个节点的下一个节点  
  21.   alert("***个节点的下一个节点:"+c_n_s.innerHTML+ "\n" + "节点中包含的HTML内容: "+c_n_s.nodeName);  
  22.    
  23. }  
  24.  

写到这里,既然标准的previousSibling,nextSibling,firstChild,lastChild,parentNode遍历方法有浏览器不兼容问题。我上面的解决方案是去掉遍历元素的相关空的#Text节点,是一个好的解决方案,但是使用起来不方便,我们何不自己写一些遍历节点的方法来代替标准的的previousSibling,nextSibling,firstChild,lastChild,parentNode。

我们的思路是利用元素是nodeType属性来判断元素是节点类型中那种节点类型,在DOM节点中我最常用的是元素节点,文本节点,属性节点,对应的类型值是元素节点nodeType=1 or ELEMENT_NODE, 文本节点 nodeType=2 or ATTRIBUTE_NODE,属性节点 nodeType=3 or TEXT_NODE,但是IE中并不支持命名常量,那就用数值吧,再配合标准的遍历属性。完全可以自己生产一些辅助函数来取代标准的遍历方式。以下一系列的辅助函数可以帮助您,他们能取代标准的previousSibling,nextSibling,firstChild,lastChild,parentNode;

  1.  
  2. //---------DOM 遍历,如果元素没找到则返回null---------//      
  3.     //---查找相关元素的前一个兄弟元素---//      
  4.    function prev(elem){      
  5.         do{      
  6.            elemelem=elem.previousSibling;      
  7.         }while(elem && elem.nodeType!=1);      
  8.         return elem;      
  9.     }      
  10.     //---查找相关元素的下一个兄弟元素---//      
  11.     function next(elem){      
  12.        do{      
  13.            elemelem=elem.nextSibling;      
  14.         }while(elem && elem.nodeType!=1);      
  15.         return elem;      
  16.     }      
  17.     //---查找***个子元素的函数---//      
  18.     function first(elem){      
  19.         elemelem=elem.firstChild;      
  20.         return elem && elem.nodeType!=1 ?next(elem):elem;      
  21.     }      
  22.     //---查找***一个子元素的函数---//      
  23.     function last(elem){      
  24.         elemelem=elem.lastChild;      
  25.         return elem && elem.nodeType!=1 ?prev(elem):elem;      
  26.     }      
  27.     //---查找父级元素的函数---//      
  28.     //num是父级元素的级次,parent(elem,2)等价于  
  29.    function parent(elem,num){      
  30.         numnum=num||1;      
  31.         for(var i=0; i
  32.             if(elem!=null){      
  33.                 elemelem=elem.parentNode;      
  34.            }      
  35.         }      
  36.        return elem;      
  37.    }   
  38.  

原文链接:http://cssrainbow.cn/tutorials/javascript/565.html

【编辑推荐】

  1. JavaScript DOM特性与应用详解
  2. JavaScript DOM修改文档树方法实例
  3. JavaScript DOM实战:创建和克隆元素 

相关内容

热门资讯

如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
施耐德电气数据中心整体解决方案... 近日,全球能效管理专家施耐德电气正式启动大型体验活动“能效中国行——2012卡车巡展”,作为该活动的...
Windows恶意软件20年“... 在Windows的早期年代,病毒游走于系统之间,偶尔删除文件(但被删除的文件几乎都是可恢复的),并弹...
20个非常棒的扁平设计免费资源 Apple设备的平面图标PSD免费平板UI 平板UI套件24平图标Freen平板UI套件PSD径向平...
规避非法攻击 用好路由器远程管... 单位在市区不同位置设立了科技服务点,每一个服务点的员工都通过宽带路由器进行共享上网,和单位网络保持联...
德国电信门户网站可实时显示全球... 德国电信周三推出一个门户网站,直观地实时提供其安装在全球各地的传感器网络检测到的网络攻击状况。该网站...
着眼MAC地址,解救无法享受D... 在安装了DHCP服务器的局域网环境中,每一台工作站在上网之前,都要先从DHCP服务器那里享受到地址动...