DOM遍历
现有用于辅助完成顺序遍历DOM结构的类型有两个,NodeIterator和Treewalker。在于DOM兼容的浏览器中,都可以访问这两个对象,IE不支持DOM遍历,使用下列代码可以检测浏览器对DOM2级遍历的支持情况:
1 var supportTraversals = document.implementation.hasFeature('Traversal','2.0'); 2 var supportNodeIterator = (typeof document.createNodeIterator == 'function'); 3 var supportTreeWalker = (typeof document.createTreeWalker == 'function');
遍历是以给定节点为根,不可能向上超出DOM根节点,以下面的HTML页面为例:
1 <html> 2 <head> 3 <title>遍历</title> 4 </head> 5 <body> 6 <div> 7 <p>Hello</p> 8 </div> 9 <span>world</span> 10 </body> 11 </html>
遍历的顺序如下:1.Document -> 2. HTML ->3.head -> 4.title ->5.Text 遍历
-> 6.body -> 7.div -> 8.p -> 9.Text Hello
-> 10.span ->11.Text World
NodeIterator
NodeIterator可以用document.createNodeIterator()方法创建其实例,这个方法接受4个参数,分别如下:
root: 作为搜索树的起点
whatToShow:表示要访问哪些节点的数字代码
filter:表示接受或拒绝某一个特定的Node
entityReferenceExpansion:Bool变量,表示是否要扩展实体引用,在HTML中无用,直接设为false即可。
看以下示例:
1 var filter = { 2 acceptNode:function(node){ 3 return node.tagName.toLowerCase() == 'p'?NodeFilter.FILTER_ACCEPT :NodeFilter.FILTER_SKIP; 4 } 5 }; 6 var iterator = document.createNodeIterator(document,NodeFilter.SHOW_ELEMENT,filter,false);
这个iterator就是对页面中所有的p遍历。可以用iterator.nextNode()和iterator.previousNode()来访问各个遍历,在访问到根节点时,会返回null。
TreeWalker
TreeWalker可以说是NodeIterator的高级版本,它在前面的nextNode和previousNode以外,还提供了一系列方法,部分如下:
parentNode():遍历到当前节点的父节点;
firstChild():遍历到当前节点的第一个子节点;
lastChild():遍历到当前节点的最后一个节点;
nextsibling():遍历到当前节点的下一个同辈节点;
perviousSibling():遍历到当前节点的前一个同辈节点;
创建TreeWalker和使用方法如下例子:
1 var filter = function(node){ 2 return node.tagName.toLowerCase() == 'p'?NodeFilter.FILTER_ACCEPT :NodeFilter.FILTER_SKIP; 3 } 4 var walker = document.createTreeWalker(document,NodeFilter.SHOW_ELEMENT,filter,false); 5 var node = walker.nextNode(); 6 while(node != null){ 7 console.log(node.tagName.toLowerCase()); 8 node = walker.nextNode(); 9 }
其中,NodeIterator中的filter也可以如上的形式编写。
范围
DOM2级定义了范围接口,可以选择一个文档的一个区域,而不用考虑结点界限。可以用createRange()创建范围,在兼容DOM的浏览器中,这个是属于document,可以用hasFeature检测是否支持
1 var supportRange = document.implementation.hasFeature('Range','2.0'); 2 var supportRange2 = (typeof document.createRange == 'function');
若支持,就可以用document.createRange()来创建范围了
创建范围后,就可以用selectNode()和selectNodeContents()来选择范围了,selectNode选择的是整个结点,而selectNodeContents选择的是该节点的所有子节点,以下面的HTML为例:
1 <html> 2 <head> 3 <title>遍历</title> 4 </head> 5 <body> 6 <div> 7 <p>Hello</p> 8 </div> 9 <span>world</span> 10 </body> 11 </html>
我们用以上的HTML创建范围:
1 var div = document.getElementsByTagName('div')[0], 2 range = document.createRange(), 3 range2 = document.createRange(); 4 range.selectNode(div); 5 range2.selectNodeContents(div);
range的范围:<div><p>Hello</p></div>
range2的范围:<p>Hello</p>
当然,要创建精细复杂的选择,就可以使用setStart()和setEnd(),都接受两个参数,一个参照结点和偏移量
选择DOM范围后就需要进行DOM操作了,在操作之前,我们需要考虑一个问题,就是精细操作以后,如果我选择的是一个结点的一部分(按上个例子,我选择了<p>Hel),如果进行删除操作,那么不是文档不完整了?其实在选择范围后,在后台会动态补上缺失的标签(按刚才的会补充成<p>Hel</p><p>llo</p>),这样就可以无误的进行操作DOM了。
操作的方法有deleteContents()—删除文档区域
extractContents()—提取文档区域,原始的在文档中的内容会删除
insertNode()—向范围选取开始处插入一个节点
cloneContents()—复制范围对象,返回一个副本
通过这些方法,就可以简单操作DOM范围了
1 var div = document.getElementsByTagName('div')[0], 2 range = document.createRange(); 3 range.selectNode(div); 4 range.deleteContents();