JavaScript的DOM進階

DOM 自身存在很多類型,在DOM 基礎課程中大部分都有所接觸,比如Element 類型:
表示的是元素節點,再比如Text 類型:表示的是文本節點。DOM 也提供了一些擴展功能。


一.DOM類型
DOM 基礎課程中,我們瞭解了DOM 的節點並且瞭解怎樣查詢和操作節點,而本身這
些不同的節點,又有着不同的類型。

1.Node 類型
Node 接口是DOM1 級就定義了,Node 接口定義了12 個數值常量以表示每個節點的類
型值。除了IE 之外,所有瀏覽器都可以訪問這個類型。

雖然這裏介紹了12 種節點對象的屬性,用的多的其實也就幾個而已。

  1. alert(Node.ELEMENT_NODE); //1,元素節點類型值 
  2. alert(Node.TEXT_NODE); //2,文本節點類型值 

我們建議使用Node 類型的屬性來代替1,2 這些阿拉伯數字,有可能大家會覺得這樣豈
不是很繁瑣嗎?並且還有一個問題就是IE 不支持Node 類型。
如果只有兩個屬性的話,用1,2 來代替會特別方便,但如果屬性特別多的情況下,1、
2、3、4、5、6、7、8、9、10、11、12,你根本就分不清哪個數字代表的是哪個節點。當然,
如果你只用1,2 兩個節點,那就另當別論了。
IE 不支持,我們可以模擬一個類,讓IE 也支持。

  1. if (typeof Node == 'undefined') { //IE 返回 
  2. window.Node = { 
  3. ELEMENT_NODE : 1, 
  4. TEXT_NODE : 3 
  5. }; 

2.Document 類型
Document 類型表示文檔,或文檔的根節點,而這個節點是隱藏的,沒有具體的元素標
籤。

  1. document; //document 
  2. document.nodeType; //9,類型值 
  3. document.childNodes[0]; //DocumentType,第一個子節點對象 
  4. document.childNodes[0].nodeType; //非IE 爲10,IE 爲8 
  5. document.childNodes[1]; //HTMLHtmlElement 
  6. document.childNodes[1].nodeName; //HTML 

如果想直接得到<html>標籤的元素節點對象HTMLHtmlElement,不必使用childNodes
屬性這麼麻煩,可以使用documentElement 即可。

  1. document.documentElement; //HTMLHtmlElement 

在很多情況下,我們並不需要得到<html>標籤的元素節點,而需要得到更常用的<body>
標籤,之前我們採用的是:document.getElementsByTagName('body')[0],那麼這裏提供一個
更加簡便的方法:document.body。

  1. document.body; //HTMLBodyElement 

在<html>之前還有一個文檔聲明:<!DOCTYPE>會作爲某些瀏覽器的第一個節點來處
理,這裏提供了一個簡便方法來處理:document.doctype。

  1. document.doctype; //DocumentType 

PS:IE8 中,如果使用子節點訪問,IE8 之前會解釋爲註釋類型Comment 節點,而
document.doctype 則會返回null。

  1. document.childNodes[0].nodeName //IE 會是#Comment 

在Document 中有一些遺留的屬性和對象合集,可以快速的幫助我們精確的處理一些任
務。

  1. //屬性 
  2. document.title; //獲取和設置<title>標籤的值 
  3. document.URL; //獲取URL 路徑 
  4. document.domain; //獲取域名,服務器端 
  5. document.referrer; //獲取上一個URL,服務器端 
  6. //對象集合 
  7. document.anchors; //獲取文檔中帶name 屬性的<a>元素集合 
  8. document.links; //獲取文檔中帶href 屬性的<a>元素集合 
  9. document.applets; //獲取文檔中<applet>元素集合,已不用 
  10. document.forms; //獲取文檔中<form>元素集合 
  11. document.p_w_picpaths; //獲取文檔中<img>元素集合 

3.Element 類型
Element 類型用於表現HTML 中的元素節點。在DOM 基礎那章,我們已經可以對元素
節點進行查找、創建等操作,元素節點的nodeType 爲1,nodeName 爲元素的標籤名。
元素節點對象在非IE 瀏覽器可以返回它具體元素節點的對象類型。

PS:以上給出了部分對應,更多的元素對應類型,直接訪問調用即可。

4.Text 類型
Text 類型用於表現文本節點類型,文本不包含HTML,或包含轉義後的HTML。文本
節點的nodeType 爲3。
在同時創建兩個同一級別的文本節點的時候,會產生分離的兩個節點。

  1. var box = document.createElement('div'); 
  2. var text = document.createTextNode('Mr.'); 
  3. var text2 = document.createTextNode(Lee!); 
  4. box.appendChild(text); 
  5. box.appendChild(text2); 
  6. document.body.appendChild(box); 
  7. alert(box.childNodes.length); //2,兩個文本節點 

PS:把兩個同鄰的文本節點合併在一起使用normalize()即可。

  1. box.normalize(); //合併成一個節點 

PS:有合併就有分離,通過splitText(num)即可實現節點分離。

  1. box.firstChild.splitText(3); //分離一個節點 

除了上面的兩種方法外,Text 還提供了一些別的DOM 操作的方法如下:

  1. var box = document.getElementById('box'); 
  2. box.firstChild.deleteData(0,2); //刪除從0 位置的2 個字符 
  3. box.firstChild.insertData(0,'Hello.'); //從0 位置添加指定字符 
  4. box.firstChild.replaceData(0,2,'Miss'); //從0 位置替換掉2 個指定字符 
  5. box.firstChild.substringData(0,2); //從0 位置獲取2 個字符,直接輸出 
  6. alert(box.firstChild.nodeValue); //輸出結果 

5.Comment 類型
Comment 類型表示文檔中的註釋。nodeType 是8,nodeName 是#comment,nodeValue
是註釋的內容。

  1. var box = document.getElementById('box'); 
  2. alert(box.firstChild); //Comment 

PS:在IE 中,註釋節點可以使用!當作元素來訪問。

  1. var comment = document.getElementsByTagName('!'); 
  2. alert(comment.length); 

6.Attr 類型
Attr 類型表示文檔元素中的屬性。nodeType 爲11,nodeName 爲屬性名,nodeValue 爲
屬性值。DOM 基礎篇已經詳細介紹過,略。


二.DOM擴展
1.呈現模式
從IE6 開始開始區分標準模式和混雜模式(怪異模式),主要是看文檔的聲明。IE 爲
document 對象添加了一個名爲compatMode 屬性,這個屬性可以識別IE 瀏覽器的文檔處於
什麼模式如果是標準模式,則返回CSS1Compat,如果是混雜模式則返回BackCompat。

  1. if (document.compatMode == 'CSS1Compat') { 
  2. alert(document.documentElement.clientWidth); 
  3. else { 
  4. alert(document.body.clientWidth); 

PS:後來Firefox、Opera 和Chrome 都實現了這個屬性。從IE8 後,又引入documentMode
新屬性,因爲IE8 有3 種呈現模式分別爲標準模式8,仿真模式7,混雜模式5。所以如果
想測試IE8 的標準模式,就判斷document.documentMode > 7 即可。


2.滾動
DOM 提供了一些滾動頁面的方法,如下:

  1. document.getElementById('box').scrollIntoView(); //設置指定可見 

3.children 屬性
由於子節點空白問題,IE 和其他瀏覽器解釋不一致。雖然可以過濾掉,但如果只是想
得到有效子節點,可以使用children 屬性,支持的瀏覽器爲:IE5+、Firefox3.5+、Safari2+、
Opera8+和Chrome,這個屬性是非標準的。

  1. var box = document.getElementById('box'); 
  2. alert(box.children.length); //得到有效子節點數目 

4.contains()方法
判斷一個節點是不是另一個節點的後代,我們可以使用contains()方法。這個方法是IE
率先使用的,開發人員無須遍歷即可獲取此信息。

  1. var box = document.getElementById('box'); 
  2. alert(box.contains(box.firstChild)); //true 

PS:早期的Firefox 不支持這個方法,新版的支持了,其他瀏覽器也都支持,Safari2.x
瀏覽器支持的有問題,無法使用。所以,必須做兼容。


在Firefox 的DOM3 級實現中提供了一個替代的方法compareDocumentPosition()方法。
這個方法確定兩個節點之間的關係。

  1. var box = document.getElementById('box'); 
  2. alert(box.compareDocumentPosition(box.firstChild)); //20 

PS:爲什麼會出現20,那是因爲滿足了4 和16 兩項,最後相加了。爲了能讓所有瀏覽
器都可以兼容,我們必須寫一個兼容性的函數。

  1. //傳遞參考節點(父節點),和其他節點(子節點) 
  2. function contains(refNode, otherNode) { 
  3. //判斷支持contains,並且非Safari 瀏覽器 
  4. if (typeof refNode.contains != 'undefined' && 
  5. !(BrowserDetect.browser == 'Safari' && BrowserDetect.version < 3)) { 
  6. return refNode.contains(otherNode); 
  7. //判斷支持compareDocumentPosition 的瀏覽器,大於16 就是包含 
  8. else if (typeof refNode.compareDocumentPosition == 'function') { 
  9. return !!(refNode.compareDocumentPosition(otherNode) > 16); 
  10. else { 
  11. //更低的瀏覽器兼容,通過遞歸一個個獲取他的父節點是否存在 
  12. var node = otherNode.parentNode; 
  13. do { 
  14. if (node === refNode) { 
  15. return true
  16. else { 
  17. node = node.parentNode; 
  18. while (node != null); 
  19. return false

三.DOM操作內容
雖然在之前我們已經學習了各種DOM 操作的方法,這裏所介紹是innerText、
innerHTML、outerText 和outerHTML 等屬性。除了之前用過的innerHTML 之外,其他三個
還麼有涉及到。


1.innerText 屬性

  1. document.getElementById('box').innerText; //獲取文本內容(如有html 直接過濾掉) 
  2. document.getElementById('box').innerText = 'Mr.Lee'//設置文本(如有html 轉義) 

PS:除了Firefox 之外,其他瀏覽器均支持這個方法。但Firefox 的DOM3 級提供了另
外一個類似的屬性:textContent,做上兼容即可通用。

  1. document.getElementById('box').textContent; //Firefox 支持 
  2. //兼容方案 
  3. function getInnerText(element) { 
  4. return (typeof element.textContent == 'string') ? 
  5. element.textContent : element.innerText; 
  6. function setInnerText(element, text) { 
  7. if (typeof element.textContent == 'string') { 
  8. element.textContent = text; 
  9. else { 
  10. element.innerText = text; 

2.innerHTML 屬性
這個屬性之前就已經研究過,不拒絕HTML。

  1. document.getElementById('box').innerHTML; //獲取文本(不過濾HTML) 
  2. document.getElementById('box').innerHTML = '<b>123</b>'//可解析HTML 

雖然innerHTML 可以插入HTML,但本身還是有一定的限制,也就是所謂的作用域元
素,離開這個作用域就無效了。

  1. box.innerHTML = "<script>alert('Lee');</script>"//<script>元素不能被執行 
  2. box.innerHTML = "<style>red;< /style>"//<style>元素不能被執行 

3.outerText
outerText 在取值的時候和innerText 一樣,同時火狐不支持,而賦值方法相當危險,他
不單替換了文本內容,還將元素直接抹去。

  1. var box = document.getElementById('box'); 
  2. box.outerText = '<b>123</b>'
  3. alert(document.getElementById('box')); //null,建議不去使用 

4.outerHTML
outerHTML 屬性在取值和innerHTML 一致,但和outerText 也一樣,很危險,賦值的之
後會將元素抹去。

  1. var box = document.getElementById('box'); 
  2. box.outerHTML = '123'
  3. alert(document.getElementById('box')); //null,建議不去使用,火狐舊版未抹去 

PS:關於最常用的innerHTML 屬性和節點操作方法的比較,在插入大量HTML 標記時
使用innerHTML 的效率明顯要高很多。因爲在設置innerHTML 時,會創建一個HTML 解
析器。這個解析器是瀏覽器級別的(C++編寫),因此執行JavaScript 會快的多。但,創建和
銷燬HTML 解析器也會帶來性能損失。最好控制在最合理的範圍內,如下:

  1. for (var i = 0; i < 10; i ++) { 
  2. ul.innerHTML = '<li>item</li>'//避免頻繁 
  3. //改 
  4. for (var i = 0; i < 10; i ++) { 
  5. a = '<li>item</li>'//臨時保存 
  6. ul.innerHTML = a; 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章