JavaScript DOM 編程之進階篇
1.樣式 ①判斷是否支援css2樣式 document.implementation.hasFeature("CSS2", "2.0"); ②訪問元素之間的樣式 a.DOM樣式屬性和方法 eg:設定和擷取元素的樣式 var div = document.createElement("div"); div.style.width = "100px"; div.style.height = "100px"; div.style.backgroundColor = "red"; document.body.appendChild(div); for( var i = 0, len = div.style.length; i < len; i++) { pro = div.style[i]; alert( pro + " = " + div.style.getPropertyValue(pro)); // 擷取各個屬性與值的索引值對 } // 擷取計算的樣式 var computedStyle = document.defaultView.getComputedStyle(div, null) || div.currentStyle; alert(computedStyle.width); alert(computedStyle.height); alert(computedStyle.backgroundColor); alert(computedStyle.border); b.計算樣式(唯讀) 值從其他樣式表摺疊影響當前元素樣式資訊 ③操作樣式表 a.可以通過兩種方法擷取css樣式表 eg: HTML部分: JS部分: // 1.用styleSheets集合 var links = document.styleSheets; for(var i = 0, len = links.length; i < len; i++) { alert(links[i].href); } // 2.先擷取link元素,在調用其的sheet||styleSheet屬性 function getStyleSheet(ele) { return ele.sheet || ele.styleSheet; } var links = document.querySelectorAll("link"); for(var i = 0, len = links.length; i < len; i++) { var sheets = getStyleSheet(links[i]); alert(sheets.href); } b.CSS規則 擷取、建立、刪除規則 eg : 對樣式規則進行讀取、插入和刪除 HTML/CSS部分: div { width : 100px; height : 100px; background : red; border : 1px solid black; } JS部分: var styleRule = { // 擷取樣式規則 get : function () { // 這個方法定義的不妥 var sheet = document.styleSheets[0]; // 擷取第一個樣式表 var rules = sheet.cssRules || sheet.rules; // 樣式規則 return rules; // 返回所有樣式規則的集合 }, /**建立樣式規則 * param sheet : 樣式表 * param selectorText : 選取器 * param cssText : css代碼 * param position : 插入規則的位置 */ insert : function (sheet, selectorText, cssText, position){ if (sheet.insertRule){ sheet.insertRule(selectorText + "{" + cssText + "}", position); } else if (sheet.addRule){ sheet.addRule(selectorText, cssText, position); } }, /**刪除樣式規則 * param sheet : 樣式表 * param index : 要刪除規則的位置 */ remove : function (sheet, index){ if (sheet.deleteRule){ sheet.deleteRule(index); } else if (sheet.removeRule){ sheet.removeRule(index); } } }; // 擷取div的css代碼 // var divCSS = styleRule.get()[0]; // alert(divCSS.cssText); // 返回第一條規則的所有css代碼 // alert(divCSS.style.width); // 返回單個屬性值 // 重設body與div的樣式 styleRule.insert(document.styleSheets[0], "body", "background : green", 0); // 第一條規則 styleRule.insert(document.styleSheets[0], "div", "background : pink", 2); // 第二條規則 // 刪除body的樣式 styleRule.remove(document.styleSheets[0], 0); ④元素大小 a.位移量 1) offsetHeight : 元素在垂直方向佔用的空間大小。 offsetHeight = height + padding + border + 捲軸 2) offsetWidth : 元素在水平方向佔用的空間大小。 offsetHeight = width + padding + border + 捲軸 3) offsetTop : 元素的上外邊框至包含元素的上內邊框之間的像素距離 4) offsetLeft : 元素的左外邊框至包含元素的左內邊框之間的像素距離 5) offsetParent : 表示包含元素的元素 eg : 擷取某個元素在頁面上的位移量 function getElementLeft(element){ var actualLeft = element.offsetLeft; // 擷取offsetLeft var current = element.offsetParent; // 擷取包含元素,父元素 while (current !== null){ // 如果父元素不存在 actualLeft += current.offsetLeft; current = current.offsetParent; } return actualLeft; } function getElementTop(element){ var actualTop = element.offsetTop; var current = element.offsetParent; while (current !== null){ actualTop += current. offsetTop; current = current.offsetParent; } return actualTop; } b.用戶端大小 1) clientHeight = height + padding-top + padding-bottom 2) clientWidth = width + padding-left + padding-right eg: 擷取視口大小 function getViewport(){ if (document.compatMode == "BackCompat"){ // ie7的混雜模式 return { width: document.body.clientWidth, height: document.body.clientHeight }; } else { return { width: document.documentElement.clientWidth, height: document.documentElement.clientHeight }; } } c.滾動大小 1) scrollHeight:在沒有捲軸的情況下,元素內容的總高度。 2) scrollWidth:在沒有捲軸的情況下,元素內容的總寬度。 3) scrollLeft:被隱藏在內容地區左側的像素數 4) scrollTop:被隱藏在內容地區上方的像素數 d.確定元素的大小 eg : 跨瀏覽器使用自身的屬性offset來判斷是否要對座標進行調整 function getBoundingClientRect(element){ var scrollTop = document.documentElement.scrollTop; var scrollLeft = document.documentElement.scrollLeft; if (element.getBoundingClientRect){ if (typeof arguments.callee.offset != "number"){ var temp = document.createElement("div"); temp.style.cssText = "position:absolute;left:0;top:0;"; document.body.appendChild(temp); arguments.callee.offset = -temp.getBoundingClientRect().top - scrollTop; document.body.removeChild(temp); temp = null; } var rect = element.getBoundingClientRect(); var offset = arguments.callee.offset; return { left: rect.left + offset, right: rect.right + offset, top: rect.top + offset, bottom: rect.bottom + offset }; } else { var actualLeft = getElementLeft(element); var actualTop = getElementTop(element); return { left: actualLeft - scrollLeft, right: actualLeft + element.offsetWidth - scrollLeft, top: actualTop - scrollTop, bottom: actualTop + element.offsetHeight - scrollTop } } } var div = document.querySelector("div"); var rect = getBoundingClientRect(div); 3.遍曆 1.NodeIterator eg: 遍曆元素,過濾出自己想要的元素 HTML部分: Hello world!
- List item 1
- List item 2
- List item 3
JS部分: var div = document.getElementById("div1"); var filter = function(node){ // 只考慮li元素 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); //輸出標籤名 LI,LI,LI node = iterator.nextNode(); } 2.TreeWalker 它除了包含NodeIterator類型的方法屬性外,還具有以下屬性方法: ①parentNode():遍曆到當前節點的父節點; ②firstChild():遍曆到當前節點的第一個子節點; ③lastChild():遍曆到當前節點的最後一個子節點; ④nextSibling():遍曆到當前節點的下一個同輩節點; ⑤previousSibling():遍曆到當前節點的上一個同輩節點。 eg: HTML: 上述一致 JS部分: var div = document.getElementById("div1"); var walker = document.createTreeWalker(div, NodeFilter.SHOW_ELEMENT, null, false); walker.firstChild(); //轉到 walker.nextSibling(); //轉到
var node = walker.firstChild(); //轉到第一個- while (node !== null) { alert(node.tagName); node = walker.nextSibling(); }4.範圍 通過範圍介面可以選取一個地區 ①判斷瀏覽器是否支援範圍操作 alert(document.implementation.hasFeature("Rang", "2.0")); alert(typeof document.createRange == "function"); ②DOM中操作範圍 a.可以通過document.createRange來建立一個範圍,它包括以下的屬性: 1) startContainer:包含範圍起點的節點(即選區中第一個節點的父節點) 2) startOffset:範圍在startContainer 中起點的位移量。 3) endContainer:包含範圍終點的節點(即選區中最後一個節點的父節點) 4) endOffset:範圍在endContainer 中終點的位移量 5) commonAncestorContainer:startContainer 和endContainer 共同的祖先節點在文檔樹中位置最深的那個。 b.用DOM範圍實現簡單選擇,可以用selectNode()和selectNodeContents(),前者包含自己,後者只包括子孫節點 eg:
Hello world!
var range1 = document.createRange();// range: Hello world!
range2 = document.createRange(); // range: Hello world! p1 = document.getElementById("p1"); range1.selectNode(p1); range2.selectNodeContents(p1); 分析:上述例子中,在調用selectNode時,startContainerendContainer和commonAncestorContainer 都是div,而startOffset是body下的一個元素的索引,即0,endOffset是p標籤加1,即1 在調用selectNodeContents時,startContainer endContainer和commonAncestorContainer都是p, 而startOffset是在p元素下的第一元素為0,而endOffset等於p下的元素的數量為2. c.另外還有一些方法,可以更精確的控制元素的範圍 1) setStartBefore(refNode):將範圍的起點設定在refNode 之前,因此refNode 也就是範圍 選區中的第一個子節點。同時會將startContainer 屬性設定為refNode.parentNode,將 startOffset 屬性設定為refNode 在其父節點的childNodes 集合中的索引。 2) setStartAfter(refNode):將範圍的起點設定在refNode 之後,因此refNode 也就不在範 圍之內了,其下一個同輩節點才是範圍選區中的第一個子節點。同時會將startContainer 屬 性設定為refNode.parentNode,將startOffset 屬性設定為refNode 在其父節點的 childNodes 集合中的索引加1。 3) setEndBefore(refNode):將範圍的終點設定在refNode 之前,因此refNode 也就不在範圍 之內了,其上一個同輩節點才是範圍選區中的最後一個子節點。同時會將endContainer 屬性 設定為refNode.parentNode,將endOffset 屬性設定為refNode 在其父節點的childNodes 集合中的索引。 4) setEndAfter(refNode):將範圍的終點設定在refNode 之後,因此refNode 也就是範圍選區 中的最後一個子節點。同時會將endContainer 屬性設定為refNode.parentNode,將 endOffset 屬性設定為refNode 在其父節點的childNodes 集合中的索引加1。 d.要實現更複雜的範圍選取操作,必須用到setStart和setEnd方法,並接受兩個參數,第一個表示參照節點,第二個為位移量;對於setStart而言,參照節點就是startContainer,而位移量則是startOffset;對於setEnd而言,參照節點就是endContainer,而位移量則是endOffset eg:我們用setStart和setEnd方法,來類比selectNode和selectNodeContents方法 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); // 同樣我們還可以選取hello中的llo到world中的o為止的字元,即llo wo這6個字元 var hello = p.firstChild.firstChild; var world = p.lastChild; rang1.setStart(hello, 2); // llo range1.setEnd(world, 3); // wor e.操作DOM範圍中的內容 1)第一個方法:deleteContents表示將選取範圍的內容從原有的元素內容中刪除,並返回之後剩下的元素 rang1.setStart(hello, 2); // llo range1.setEnd(world, 3); // wor range.deleteContents(); // 剩下的元素為:Herld!
2) extractContents()會從文檔中移除範圍選區,且可以將範圍的內容插入到文檔中的其他地方。 var fragment = range.extractContents(); p1.parentNode.appendChild(fragment);// 將llowor添加到中去 3) 還一種做法,即使用cloneContents()建立範圍對象的一個副本,然後在文檔的其他地方插入該副本 var fragment = range.cloneContents(); p1.parentNode.appendChild(fragment); // Hello world!
llo wo f.插入DOM範圍中的內容,用insertNode方法,將指定的節點添加到選取範圍內容的最開始位置 var span = document.createElement("span"); span.style.color = "red"; span.appendChild(document.createTextNode("Inserted text")); range.insertNode(span); 結果:HeInserted textllo world
g.還可以環繞範圍新增內容,用surroundContents,接受一個參數為環繞範圍內容的節點,該操作執行以下驟: 1) 提取出範圍中的內容(類似執行extractContent()); 2) 將給定節點插入到文檔中原來範圍所在的位置上; 3) 將文檔片段的內容添加到給定節點中。 range.selectNode(hello); var span = document.createElement("span"); span.style.backgroundColor = "yellow"; range.surroundContents(span); 結果:Hello world!
h.摺疊DOM範圍,是指範圍未選取文檔的任何部分的內容。使用collapse(布爾值), 當為true表示摺疊到開始,false表示摺疊到結束位置,而屬性collapsed表示是否摺疊 Paragraph 1
Paragraph 2
var p1 = document.getElementById("p1"), p2 = document.getElementById("p2"), range = document.createRange(); range.setStartAfter(p1); range.setStartBefore(p2); alert(range.collapsed); //輸出true i.比較DOM範圍,用比較點.compareBoundaryPoints(比較參數,參照點)來比較,當比較點位於參照點以前, 返回-1;當相等返回0;當比較點在參照點之後,返回1;比較參數如下: 1)Range.START_TO_START(0):比較第一個範圍和第二個範圍的起點; 2)Range.START_TO_END(1):比較第一個範圍的起點和第二個範圍的終點; 3)Range.END_TO_END(2):比較第一個範圍和第二個範圍的終點; 4)Range.END_TO_START(3):比較第一個範圍的終點和第一個範圍的起點。 eg: var range1 = document.createRange(); var range2 = document.createRange(); var p1 = document.getElementById("p1"); range1.selectNodeContents(p1); // Hello world! range2.selectNodeContents(p1); range2.setEndBefore(p1.lastChild); // Hello alert(range1.compareBoundaryPoints(Range.START_TO_START, range2)); //0 alert(range1.compareBoundaryPoints(Range.END_TO_END, range2)); //1 j.複製DOM範圍,用cloneRange() k.清除DOM範圍,用detach() eg: range.detach(); //從文檔中分離 range = null; //解除引用 ③Less IE8操作範圍 a.用IE範圍實現簡單的選擇 eg: Hello world!
var range = document.body.createTextRange(); var found = range.findText("Hello"); alert(found); //true alert(range.text); //"Hello" // IE 中與DOM 中的selectNode()方法最接近的方法是moveToElementText() range.moveToElementText(p1);// 選取p1以及p1的子項目 // parentElement()方法倒是與DOM 的commonAncestorContainer 屬性類似 var ancestor = range.parentElement(); // div b.使用IE範圍實現複雜的選擇 move()、moveStart()、moveEnd()和expand()方法,接受兩個參數,移動單位和移動單位的數量 移動單位如下: 1) "character":逐個字元地移動。 2) "word":逐個單詞(一系列非空白字元)地移動。 3) "sentence":逐個句子(一系列以句號、問號或歎號結尾的字元)地移動。 4) "textedit":移動到當前範圍選區的開始或結束位置。 range.moveStart("word", 2); //起點移動2 個單詞 range.moveEnd("character", 1); //終點移動1 個字元 range.move("character", 5); //移動5 個字元 c.操作IE範圍中的內容。讀取用findText(文本),修改用rang.text = value;要插入帶html的文本用pasteHMTL var range = document.body.createTextRange(); range.findText("Hello"); // 讀取 range.text = "Howdy"; // 修改 range.pasteHTML("Howdy");// 插入帶html的文本 d.摺疊IE範圍。摺疊ie的範圍,也用collapse(布爾)值,但是判斷需要用到boundingWidth == 0屬性判斷 range.collapse(true); //摺疊到起點 var isCollapsed = (range.boundingWidth == 0); e.比較範圍,用compareEndPoints()和isEqual()以及isRnage(), var range1 = document.body.createTextRange(); var range2 = document.body.createTextRange(); range1.findText("Hello world!"); range2.findText("Hello"); alert(range1.compareEndPoints("StartToStart", range2)); //0 alert(range1.compareEndPoints("EndToEnd", range2)); //1 alert("range1.isEqual(range2): " + range1.isEqual(range2)); //false alert("range1.inRange(range2):" + range1.inRange(range2)); //true f.複製IE範圍。用duplicate複製範圍節點 var newRange = range.duplicate();// 新建立的範圍會帶有與原範圍完全相同的屬性。