JavaScript操作HTML DOM節點的基礎教程,javascriptdom
因為 DOM 的存在,這使我們可以通過 JavaScript 來擷取、建立、修改、或刪除節點。
NOTE:下面提供的例子中的 element 均為元素節點。
擷取節點
父子關係
element.parentNodeelement.firstChild/element.lastChildelement.childNodes/element.children
兄弟關係
element.previousSibling/element.nextSiblingelement.previousElementSibling/element.nextElementSibling
通過節點直接的關係擷取節點會導致代碼維護性大大降低(節點之間的關係變化會直接影響到擷取節點),而通過介面則可以有效解決此問題。
通過節點直接的關係擷取節點會導致代碼維護性大大降低(節點之間的關係變化會直接影響到擷取節點),而通過介面則可以有效解決此問題。
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>ELEMENT_NODE & TEXT_NODE</title></head><body> <ul id="ul"> <li>First</li> <li>Second</li> <li>Third</li> <li>Fourth</li> </ul> <p>Hello</p> <script type="text/javascript"> var ulNode = document.getElementsByTagName("ul")[0]; console.log(ulNode.parentNode); //<body></body> console.log(ulNode.previousElementSibling); //null console.log(ulNode.nextElementSibling); //<p>Hello</p> console.log(ulNode.firstElementChild); //<li>First</li> console.log(ulNode.lastElementChild); //<li>Fourth</li> </script></body></html>
NTOE:細心的人會發現,在節點遍曆的例子中,body、ul、li、p節點之間是沒有空格的,因為如果有空格,那麼空格就會被當做一個TEXT節點,從而用ulNode.previousSibling擷取到得就是一個空的文本節點,而不是 <li>First</li> 節點了。即節點遍曆的幾個屬性會得到所有的節點類型,而元素遍曆只會得到相對應的元素節點。一般情況下,用得比較多得還是元素節點的遍曆屬性。
實現瀏覽器安全色版的element.children
有一些低版本的瀏覽器並不支援 element.children 方法,但我們可以用下面的方式來實現相容。
<html lang><head> <meta charest="utf-8"> <title>Compatible Children Method</title></head><body id="body"> <div id="item"> <div>123</div> <p>ppp</p> <h1>h1</h1> </div> <script type="text/javascript"> function getElementChildren(e){ if(e.children){ return e.children; }else{ /* compatible other browse */ var i, len, children = []; var child = element.firstChild; if(child != element.lastChild){ while(child != null){ if(child.nodeType == 1){ children.push(child); } child = child.nextSibling; } }else{ children.push(child); } return children; } } /* Test method getElementChildren(e) */ var item = document.getElementById("item"); var children = getElementChildren(item); for(var i =0; i < children.length; i++){ alert(children[i]); } </script></body></html>
NOTE:此相容方法為初稿,還未進行相容性測試。
介面擷取元素節點
getElementByIdgetElementsByTagNamegetElementsByClassNamequerySelectorquerySelectorAll
getElementById
擷取文檔中指定 id 的節點對象。
var element = document.getElementById('id');getElementsByTagName
動態擷取具有指定標籤元素節點的集合(其傳回值會被 DOM 的變化所影響,其值會發生變化)。此介面可直接通過元素而擷取,不必直接作用於 document 之上。
// 樣本var collection = element.getElementsByTagName('tagName');// 擷取指定元素的所有節點var allNodes = document.getElementsByTagName('*');// 擷取所有 p 元素的節點var elements = document.getElementsByTagName('p');// 取出第一個 p 元素var p = elements[0];
getElementsByClassName
擷取指定元素中具有指定 class 的所有節點。多個 class 可的選擇可使用空格分隔,與順序無關。
var elements = element.getElementsByClassName('className');
NOTE:IE9 及一下版本不支援 getElementsByClassName
相容方法
function getElementsByClassName(root, className) { // 特性偵測 if (root.getElementsByClassName) { // 優先使用 W3C 規範介面 return root.getElementsByClassName(className); } else { // 擷取所有後代節點 var elements = root.getElementsByTagName('*'); var result = []; var element = null; var classNameStr = null; var flag = null; className = className.split(' '); // 選擇包含 class 的元素 for (var i = 0, element; element = elements[i]; i++) { classNameStr = ' ' + element.getAttribute('class') + ' '; flag = true; for (var j = 0, name; name = className[j]; j++) { if (classNameStr.indexOf(' ' + name + ' ') === -1) { flag = false; break; } } if (flag) { result.push(element); } } return result; }}
querySelector / querySelectorAll
擷取一個 list (其返回結果不會被之後 DOM 的修改所影響,擷取後不會再變化)符合傳入的 CSS 選取器的第一個元素或全部元素。
var listElementNode = element.querySelector('selector');var listElementsNodes = element.querySelectorAll('selector');var sampleSingleNode = element.querySelector('#className');var sampleAllNodes = element.querySelectorAll('#className');
NOTE: IE9 一下不支援 querySelector 與 querySelectorAll
建立節點
建立節點 -> 設定屬性 -> 插入節點
var element = document.createElement('tagName');
修改節點
textContent
擷取或設定節點以及其後代節點的常值內容(對於節點中的所有常值內容)。
element.textContent; // 擷取element.textContent = 'New Content';
NOTE:不支援 IE 9 及其一下版本。
innerText (不符合 W3C 規範)
擷取或設定節點以及節點後代的常值內容。其作用於 textContent 幾乎一致。
element.innerText;
NOTE:不符合 W3C 規範,不支援 FireFox 瀏覽器。
FireFox 相容方案
if (!('innerText' in document.body)) { HTMLElement.prototype.__defineGetter__('innerText', function(){ return this.textContent; }); HTMLElement.prototype.__defineSetter__('innerText', function(s) { return this.textContent = s; });}
插入節點
appendChild
在指定的元素內追加一個元素節點。
var aChild = element.appendChild(aChild);
insertBefore
在指定元素的指定節點前插入指定的元素。
var aChild = element.insertBefore(aChild, referenceChild);
刪除節點
刪除指定的節點的子項目節點。
var child = element.removeChild(child);
innerHTML
擷取或設定指定節點之中所有的 HTML 內容。替換之前內部所有的內容並建立全新的一批節點(去除之前添加的事件和樣式)。innerHTML 不檢查內容,直接運行並替換原先的內容。
NOTE:只建議在建立全新的節點時使用。不可在使用者可控的情況下使用。
var elementsHTML = element.innerHTML;
存在的問題+
- 低版本 IE 存在記憶體泄露
- 安全問題(使用者可以在名稱中運行指令碼代碼)
PS: appendChild() , insertBefore()插入節點需注意的問題
使用appendChild()和insertBefore()插入節點都會返回給插入的節點,
//由於這兩種方法操作的都是某個節點的子節點,所以必須現取得父節點,代碼中 someNode 表示父節點 //使用appendChild()方法插入節點 var returnedNode = someNode.appendChild(newNode); alert(returnedNode == newNode) //true //使用insertBefore()方法插入節點 var returnedNode = someNode.appendChild(newNode); alert(returnedNode == newNode) //true
值得注意的是,如果這兩種方法插入的節點原本已經存在與文檔樹中,那麼該節點將會被移動到新的位置,而不是被複製。
<div id="test"> <div>adscasdjk</div> <div id="a">adscasdjk</div> </div> <script type="text/javascript"> var t = document.getElementById("test"); var a = document.getElementById('a'); //var tt = a.cloneNode(true); t.appendChild(a); </script>
在這段代碼中,頁面輸出的結果和沒有Javascript時是一樣的,元素並沒有被複製,由於元素本來就在最後一個位置,所以就和沒有操作一樣。如果把id為test的元素的兩個子項目點換位置,就可以在firbug中看到這兩個div已經被調換了位置。
如果我們希望把id為a的元素複製一個,然後添加到文檔中,那麼必須使被複製的元素現脫離文檔流。這樣被添加複製的節點被添加到文檔中之後就不會影響到文檔流中原本的節點。即我們可以把複製的元素放到文檔的任何地方,而不影響被複製的元素。下面使用了cloneNode()方法,實現節點的深度複製,使用這種方法複製的節點會脫離文檔流。當然,我不建議使用這種方法複製具有id屬性的元素。因為在文檔中id值是唯一的。
<div id="test"> <div>adscasdjk</div> <div id="a">adscasdjk</div> </div> <script type="text/javascript"> var t = document.getElementById("test"); var a = document.getElementById('a'); var tt = a.cloneNode(true); t.appendChild(tt); </script>
相似的操作方法還有 removeNode(node)刪除一個節點,並返回該節;replaceNode(newNode,node)替換node節點,並返回該節點。這兩種方法相對來說更容易使用一些。
您可能感興趣的文章:
- JavaScript中對DOM節點的訪問、建立、修改、刪除
- javascript將DOM節點添加到文檔的方法執行個體分析
- javascript擷取dom的下一個節點方法
- JavaScript DOM節點添加樣本
- javascript 擷取HTML DOM父、子、臨近節點
- js和jquery對dom節點的操作(建立/追加)
- JS構建頁面的DOM節點結構的實現代碼
- js中使用DOM複製(複製)指定節點名資料到新的XML檔案中的代碼
- javascript dom操作之cloneNode文本節點複製提示
- Js 擷取HTML DOM節點元素的方法小結
- Javascript入門學習第八篇 js dom節點屬性說明
- JavaScript 節點操作 以及DOMDocument屬性和方法