DOM2 級標准定義了兩個用於完成順序遍歷 DOM 結構的類型:NodeIterator 和 TreeWalker。它們都能夠基於給定的起點對 DOM 結構進行深度優先遍歷。與 DOM 兼容的瀏覽器(Firefox 1+、Safari 1.3+、Opera 7.6+、Chrome 0.2+)都支持這兩個類型。IE 不支持!以下代碼可以檢測瀏覽器是否支持 DOM2 級遍歷:
var supportsTraversals = document.implementation.hasFeature("Traversal","2.0");
var supportsNodeIterator = (typeof document.createNodeIterator == "function");
var supportsTreeWalker = (typeof document.createTreeWalker == "function");
遍歷以給定的節點為根,不會超出 DOM 樹的根節點! 我們以下面的 HTML 頁面為例: <!DOCTYPE html>
<html>
<head>
<title>Example</title>
</head>
<body>
<p><b>Hello</b> world!</p>
</body>
</html>
下面的圖示給出了深度遍歷的順序:
使用 document.createNodeIterator() 方法創建一個 NodeIterator 實例。它接受四個參數:
參數名 | 說明 |
---|---|
root | 樹中某個節點作為搜索起點。 |
whatToShow | 要訪問哪些節點的數字代碼。 |
filter | NodeFilter 對象,用於過濾某些節點的函數。 |
entityReferenceExpansion | 布爾值,是否擴展實體引用。它在 HTML 中無用處。 |
whatToShow 是一個位掩碼,通過應用一個或者多個過濾器來確定要訪問的節點。它的值在 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 = odeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT;
可以使用 filter 參數來指定自定義的 NodeFilter 對象。每個 NodeFilter 對象有一個 acceptNode() 方法;如果應該訪問某個節點,就返回 NodeFilter.FILTER_ACCEPT
;如果不應該訪問,就返回 NodeFilter.FITLER_SKIP
。由於 NodeFilter 對象是抽象類型,所以只能創建一個包含 acceptNode() 方法的對象,然后將它傳給 createNodeIterator()。
現在創建一個只顯示 <p>
元素的節點迭代器:
var filter = {
acceptNode: function(node){
return node.tagName.toLowerCase() == "p" ? NodeFilter.FILTER_ACCEPT : NodeFilter.FITLER_SKIP;
}
};
var iterator = document.createNodeIterator(root,NodeFilter.SHOW_ELEMENT,filter,false);
第三個參數也可以是一個與 acceptNode() 方法類似的函數: var filter = function(node){
return node.tagName.toLowerCase() == "p" ? NodeFilter.FILTER_ACCEPT : NodeFilter.FITLER_SKIP;
}
如果不指定過濾器,那么第三個參數傳入 null。 下面創建一個能夠訪問所有類型節點的 NodeIterator: var iterator = document.createNodeIterator(root,NodeFilter.SHOW_ALL,null,false);
NodeIterator 有兩個方法:
剛剛創建的 NodeIterator 對象,有一個內部指針指向根節點,所以第一次調用 nextNode() 會返回根節點,當遍歷到最后一個節點時,再調用 nextNode() 會返回 null。previousNode() 的機制與 nextNode() 類似。
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>遍歷某個元素中的所有元素(加上過濾器)</title>
</head>
<body>
<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>
<script type="text/javascript">
var div = document.getElementById("div1");
var filter = function (node) {
return node.tagName.toLowerCase() == "li" ?
NodeFilter.FILTER_ACCEPT :
NodeFilter.FILTER_SKIP;
};
var iterator = document.createNodeIterator(div, NodeFilter.SHOW_ELEMENT, filter, false);
var node = iterator.nextNode();
while (node !== null) {
console.log(node.tagName);//輸出標簽名
node = iterator.nextNode();
}
</script>
</body>
</html>
如果只想返回 <li>
元素,可以加一個過濾器:
var div = document.getElementById("div1");
var filter = function (node) {
return node.tagName.toLowerCase() == "li" ?
NodeFilter.FILTER_ACCEPT :
NodeFilter.FILTER_SKIP;
};
var iterator = document.createNodeIterator(div, NodeFilter.SHOW_ELEMENT, filter, false);
var node = iterator.nextNode();
while (node !== null) {
console.log(node.tagName);//輸出標簽名
node = iterator.nextNode();
}
注意: Firefox 3.5 之前的版本沒有實現 createNodeIterator() 方法!
它除了包括 nextNode() 、previousNode() 之外,還包括這些方法:
方法名 | 說明 |
---|---|
parentNode() | 遍歷到當前節點的父節點 |
firstChild() | 遍歷到當前節點的第一個子節點 |
lastChild() | 遍歷到當前節點的最后一個子節點 |
nextSibling() | 遍歷到當前節點的下一個同輩節點 |
previsousSibling() | 遍歷到當前節點的上一個同輩節點 |
使用 document.createTreeWalker() 創建 TreeWalker 對象,它接受的 4 個參數與 createNodeIterator() 方法相同:
var div = document.getElementById("div1");
var filter = function (node) {
return node.tagName.toLowerCase() == "li" ?
NodeFilter.FILTER_ACCEPT :
NodeFilter.FILTER_SKIP;
};
var iterator = document.createTreeWalker(div, NodeFilter.SHOW_ELEMENT, filter, false);
var node = iterator.nextNode();
while (node !== null) {
console.log(node.tagName);//輸出標簽名
node = iterator.nextNode();
}
在 TreeWalker 中,還可以返回 NodeFilter.FILTER_REJECT
!它與 NodeFilter.FILTER_SKIP
不同之處是,NodeFilter.FILTER_SKIP
會跳過相應的節點,並繼續執行到子樹中的下一個節點,而 NodeFilter.FILTER_REJECT
會跳過相應的節點,並跳過這個節點的整個子樹!
TreeWalker 能夠在 DOM 結構中沿着任何方向移動,很厲害吧 O(∩_∩)O~。比如我們把之前的例子改造下,可以不用過濾器,就可以取得所有 <li>
元素:
var div = document.getElementById("div1");
var walker = document.createTreeWalker(div, NodeFilter.SHOW_ELEMENT, null, false);
walker.firstChild();//轉到 <p>
walker.nextSibling();//轉到 <ul>
var node = walker.firstChild();//轉到第一個 <li>
while (node !== null) {
console.log(node.tagName);
node = walker.nextSibling();
}
TreeWalker 有一個叫做 currentNode 的屬性,它表示的是,在上一次遍歷中返回的節點。通過修改它也可以修改當前遍歷繼續執行的起點,比如:
var node = walker.nextNode();
console.log(node ==== walker.currentNode);//true
walker.currentNode = document.body;//修改了起點
因為 IE 沒有對應的類型和方法,所以幾乎沒有跨瀏覽器的遍歷方案!
本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。