1. 程式人生 > >《Javascript 高階程式設計(第三版)》筆記0x15 DOM2和DOM3:遍歷、範圍

《Javascript 高階程式設計(第三版)》筆記0x15 DOM2和DOM3:遍歷、範圍

目錄

遍歷

    NodeIterator

     TreeWalker

範圍

    DOM中的範圍

        用 DOM 範圍實現簡單選擇

        用 DOM 範圍實現複雜選擇

        操作 DOM 範圍中的內容

         插入 DOM 範圍中的內容

        摺疊 DOM 範圍

        比較 DOM 範圍

         複製 DOM 範圍

        清理 DOM 範圍


遍歷

        “DOM2 級遍歷和範圍”模組定義了兩個用於輔助完成順序遍歷 DOM 結構的型別: NodeIterator和 TreeWalker。這兩個型別能夠基於給定的起點對 DOM 結構執行深度優先(depth-first)的遍歷操作。在與 DOM 相容的瀏覽器中(Firefox 1 及更高版本、 Safari 1.3 及更高版本、 Opera 7.6 及更高版本、 Chrome0.2 及更高版本),都可以訪問到這些型別的物件。 IE 不支援 DOM 遍歷。

var supportsTraversals = document.implementation.hasFeature("Traversal", "2.0");
var supportsNodeIterator = (typeof document.createNodeIterator == "function");
var supportsTreeWalker = (typeof document.createTreeWalker == "function");

<!DOCTYPE html>
<html>
	<head>
		<title>Example</title>
	</head>
	<body>
		<p><b>Hello</b> world!</p>
	</body>
</html>
以 document 為根節點的 DOM 樹進行深度優先遍歷的先後順序

 

    NodeIterator

    NodeIterator 型別是兩者中比較簡單的一個,可以使用 document.createNodeIterator()方法建立它的新例項。這個方法接受下列 4 個引數。
    root:想要作為搜尋起點的樹中的節點。
    whatToShow:表示要訪問哪些節點的數字程式碼。whatToShow 引數是一個位掩碼,通過應用一或多個過濾器(filter)來確定要訪問哪些節點。
    filter:是一個 NodeFilter 物件,或者一個表示應該接受還是拒絕某種特定節點的函式。
    entityReferenceExpansion:布林值,表示是否要擴充套件實體引用。這個引數在 HTML 頁面中沒有用,因為其中的實體引用不能擴充套件。

//建立一個只顯示<p>元素的節點迭代器
var filter = {
	acceptNode: function(node){
		return node.tagName.toLowerCase() == "p" ?
		NodeFilter.FILTER_ACCEPT :
		NodeFilter.FILTER_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.FILTER_SKIP;
};
var iterator = document.createNodeIterator(root, NodeFilter.SHOW_ELEMENT,filter, false);

//建立一個能夠訪問所有型別節點的簡單的 NodeIterator
var iterator = document.createNodeIterator(document, NodeFilter.SHOW_ALL,null, false);

        NodeIterator 型別的兩個主要方法是 nextNode()和 previousNode()。顧名思義,在深度優先的 DOM 子樹遍歷中, nextNode()方法用於向前前進一步,而 previousNode()用於向後後退一步。

<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>
//遍歷<div>元素中的所有元素
var div = document.getElementById("div1");
var iterator = document.createNodeIterator(div, NodeFilter.SHOW_ELEMENT,null, false);
var node = iterator.nextNode();
while (node !== null) {
	alert(node.tagName); //輸出標籤名
	node = iterator.nextNode();
}

//只返回遍歷中遇到的<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) {
	alert(node.tagName); //輸出標籤名
	node = iterator.nextNode();
}

     TreeWalker

    TreeWalker 是 NodeIterator 的一個更高階的版本。除了包括 nextNode()和 previousNode()在內的相同的功能之外,這個型別還提供了下列用於在不同方向上遍歷 DOM 結構的方法。
    parentNode():遍歷到當前節點的父節點;
    firstChild():遍歷到當前節點的第一個子節點;
    lastChild():遍歷到當前節點的最後一個子節點;
    nextSibling():遍歷到當前節點的下一個同輩節點;
    previousSibling():遍歷到當前節點的上一個同輩節點

var div = document.getElementById("div1");
var filter = function(node){
	return node.tagName.toLowerCase() == "li"?
		NodeFilter.FILTER_ACCEPT :
		NodeFilter.FILTER_SKIP;
};
var walker= document.createTreeWalker(div, NodeFilter.SHOW_ELEMENT,filter, false);
var node = iterator.nextNode();
while (node !== null) {
	alert(node.tagName); //輸出標籤名
	node = iterator.nextNode();
}

//使用 TreeWalker遍歷 DOM 樹,即使不定義過濾器,也可以取得所有<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) {
	alert(node.tagName);
	node = walker.nextSibling();
}

範圍

    DOM中的範圍

        用 DOM 範圍實現簡單選擇

<!DOCTYPE html>
<html>
	<body>
		<p id="p1"><b>Hello</b> world!</p>
	</body>
</html>
var range1 = document.createRange();
	range2 = document.createRange();
	p1 = document.getElementById("p1");
range1.selectNode(p1);//選擇整個節點,包括其子節點
range2.selectNodeContents(p1);//只選擇節點的子節點

        用 DOM 範圍實現複雜選擇

var range1 = document.createRange();
	range2 = document.createRange();
	p1 = document.getElementById("p1");
	p1Index = -1;
	i, len;
for (i=0, len=p1.parentNode.childNodes.length; i < len; i++) {
	if (p1.parentNode.childNodes[i] == p1) {
		p1Index = i;
		break;
	}
}
range1.setStart(p1.parentNode, p1Index);
range1.setEnd(p1.parentNode, p1Index + 1);
range2.setStart(p1, 0);
range2.setEnd(p1, p1.childNodes.length);

        操作 DOM 範圍中的內容

var p1 = document.getElementById("p1");
	helloNode = p1.firstChild.firstChild;
	worldNode = p1.lastChild;
	range = document.createRange();
range.setStart(helloNode, 2);
range.setEnd(worldNode, 3);
range.deleteContents();

var p1 = document.getElementById("p1");
	helloNode = p1.firstChild.firstChild;
	worldNode = p1.lastChild;
	range = document.createRange();
range.setStart(helloNode, 2);
range.setEnd(worldNode, 3);
var fragment = range.extractContents();
p1.parentNode.appendChild(fragment);

//使用 cloneContents()建立範圍物件的一個副本,然後在文件的其他地方插入該副本。
var p1 = document.getElementById("p1"),
	helloNode = p1.firstChild.firstChild,
	worldNode = p1.lastChild,
	range = document.createRange();
range.setStart(helloNode, 2);
range.setEnd(worldNode, 3);
var fragment = range.cloneContents();
p1.parentNode.appendChild(fragment);

         插入 DOM 範圍中的內容

<span style="color: red">Inserted text</span>
var p1 = document.getElementById("p1");
	helloNode = p1.firstChild.firstChild;
	worldNode = p1.lastChild;
	range = document.createRange();
range.setStart(helloNode, 2);
range.setEnd(worldNode, 3);
var span = document.createElement("span");
span.style.color = "red";
span.appendChild(document.createTextNode("Inserted text"));
range.insertNode(span);
<p id="p1"><b>He<span style="color: red">Inserted text</span>llo</b> world</p>

        摺疊 DOM 範圍

        指範圍中未選擇文件的任何部分。可以用文字框來描述摺疊範圍的過程。假設文字框中有一行文字,你用滑鼠選擇了其中一個完整的單詞。然後,你單擊滑鼠左鍵,選區消失,而游標則落在了其中兩個字母之間。同樣,在摺疊範圍時,其位置會落在文件中的兩個部分之間,可能是範圍選區的開始位置,也可能是結束位置。

        比較 DOM 範圍

        在有多個範圍的情況下,可以使用 compareBoundaryPoints()方法來確定這些範圍是否有公共的邊界(起點或終點)。這個方法接受兩個引數:表示比較方式的常量值和要比較的範圍。表示比較方式的常量值如下所示。
    Range.START_TO_START(0):比較第一個範圍和第二個範圍的起點;
    Range.START_TO_END(1):比較第一個範圍的起點和第二個範圍的終點;
    Range.END_TO_END(2):比較第一個範圍和第二個範圍的終點;
    Range.END_TO_START(3):比較第一個範圍的終點和第一個範圍的起點。 

var range1 = document.createRange();
var range2 = document.createRange();
var p1 = document.getElementById("p1");
range1.selectNodeContents(p1);
range2.selectNodeContents(p1);
range2.setEndBefore(p1.lastChild);
alert(range1.compareBoundaryPoints(Range.START_TO_START, range2)); //0
alert(range1.compareBoundaryPoints(Range.END_TO_END, range2)); //1

         複製 DOM 範圍

var newRange = range.cloneRange();

        清理 DOM 範圍

range.detach(); //從文件中分離
range = null; //解除引用