內容提綱:html
1.DOM類型node
2.DOM擴展瀏覽器
3.DOM操做內容性能優化
一.DOM類型服務器
DOM基礎篇中,咱們瞭解了DOM的節點而且瞭解怎樣查詢和操做節點,而自己這些不一樣的節點,又有着不一樣的類型。app
DOM類型dom
類型名函數 |
說明性能 |
Node學習 |
表示全部類型值的統一接口,IE不支持 |
Document |
表示文檔類型 |
Element |
表示元素節點類型 |
Text |
表示文本節點類型 |
Comment |
表示文檔中的註釋類型 |
CDATASection |
表示CDATA區域類型 |
DocumentType |
表示文檔聲明類型 |
DocumentFragment |
表示文檔片斷類型 |
Attr |
表示屬性節點類型 |
1.Node類型
Node接口是DOM1級就定義了,Node接口定義了12個數值常量以表示每一個節點的類型值。除了IE以外,全部瀏覽器均可以訪問這個類型。
Node的常量
常量名 |
說明 |
nodeType值 |
ELEMENT_NODE |
元素 |
1 |
ATTRIBUTE_NODE |
屬性 |
2 |
TEXT_NODE |
文本 |
3 |
CDATA_SECTION_NODE |
CDATA |
4 |
ENTITY_REFERENCE_NODE |
實體參考 |
5 |
ENTITY_NODE |
實體 |
6 |
PROCESSING_INSTRUCETION_NODE |
處理指令 |
7 |
COMMENT_NODE |
註釋 |
8 |
DOCUMENT_NODE |
文檔根 |
9 |
DOCUMENT_TYPE_NODE |
doctype |
10 |
DOCUMENT_FRAGMENT_NODE |
文檔片斷 |
11 |
NOTATION_NODE |
符號 |
12 |
雖然這裏介紹了12種節點對象的屬性,用的多的其實也就幾個而已。
alert(Node.ELEMENT_NODE); //1,元素節點類型值
alert(Node.TEXT_NODE); //2,文本節點類型值
咱們建議使用Node類型的屬性來代替1,2這些阿拉伯數字,有可能你們會以爲這樣豈不是很繁瑣嗎?而且還有一個問題就是IE不支持Node類型。
若是隻有兩個屬性的話,用1,2來代替會特別方便,但若是屬性特別多的狀況下,一、二、三、四、五、六、七、八、九、十、十一、12,你根本就分不清哪一個數字表明的是哪一個節點。固然,若是你只用1,2兩個節點,那就另當別論了。
IE不支持,咱們能夠模擬一個類,讓IE也支持。
1 if (typeof Node == 'undefined') { //IE返回 2 3 window.Node = { 4 5 ELEMENT_NODE : 1, 6 7 TEXT_NODE : 3 8 9 }; 10 11 }
2.Document類型
Document類型表示文檔,或文檔的根節點,而這個節點是隱藏的,沒有具體的元素標籤。
alert(document); //document
document.nodeType; //9,類型值
document.childNodes[0]; //DocumentType,第一個子節點對象
document.childNodes[0].nodeType; //非IE爲10,IE爲8
document.childNodes[0].nodeName; //IE爲#comment,非IE爲html
document.childNodes[1]; //HTMLHtmlElement
document.childNodes[1].nodeName; //HTML
若是想直接獲得<html>標籤的元素節點對象HTMLHtmlElement,沒必要使用childNodes屬性這麼麻煩,可使用documentElement便可。
document.documentElement; //HTMLHtmlElement
在不少狀況下,咱們並不須要獲得<html>標籤的元素節點,而須要獲得更經常使用的<body>標籤,以前咱們採用的是:document.getElementsByTagName('body')[0],那麼這裏提供一個更加簡便的方法:document.body。
document.body; //HTMLBodyElement
在<html>以前還有一個文檔聲明:<!DOCTYPE>會做爲某些瀏覽器的第一個節點來處理,這裏提供了一個簡便方法來處理:document.doctype。
document.doctype; //DocumentType
alert(document.doctype); //DocumentType, IE會顯示null
PS:IE8中,若是使用子節點訪問,IE8以前會解釋爲註釋類型Comment節點(非IE返回爲html),而document.doctype則會返回null。
document.childNodes[0].nodeName //IE會是#Comment(上面已經說過了)
在Document中有一些遺留的屬性和對象合集,能夠快速的幫助咱們精確的處理一些任務。
//屬性
document.title; //獲取和設置<title>標籤的值
document.URL; //獲取URL路徑
document.domain; //獲取域名,服務器端
document.referrer; //獲取上一個URL,服務器端
//對象集合
document.anchors; //獲取文檔中帶name屬性的<a>元素集合
document.links; //獲取文檔中帶href屬性的<a>元素集合
document.applets; //獲取文檔中<applet>元素集合,已不用
document.forms; //獲取文檔中<form>元素集合
document.images; //獲取文檔中<img>元素集合
3.Element類型
Element類型用於表現HTML中的元素節點。在DOM基礎篇中,咱們已經能夠對元素節點進行查找、建立等操做,元素節點的nodeType爲1,nodeName爲元素的標籤名(tagName)。
元素節點對象在非IE瀏覽器能夠返回它具體元素節點的對象類型。
元素對應類型表
元素名 |
類型 |
HTML |
HTMLHtmlElement |
DIV |
HTMLDivElement |
BODY |
HTMLBodyElement |
P |
HTMLParamElement |
PS:以上只給出了部分對應,更多的元素對應類型,直接訪問調用便可。
4.Text類型
Text類型用於表現文本節點類型,文本不包含HTML,或者能夠包含轉義後的HTML。文本節點的nodeType爲3。
問題:在同時建立兩個同一級別的文本節點的時候,會產生分離的兩個節點。
var box = document.createElement('div');
var text1 = document.createTextNode('Mr.');
var text2 = document.createTextNode(‘Wang!’);
box.appendChild(text1);
box.appendChild(text2);
document.body.appendChild(box);
alert(box.childNodes.length); //2,兩個文本節點
PS:把兩個同鄰的文本節點合併在一塊兒使用normalize()便可。
box.normalize(); //合併成一個節點
PS:有合併就有分離,經過splitText(num)便可實現節點分離。
box.firstChild.splitText(3); //分離一個節點,參數表示分離位置
除了上面的兩種方法外,Text還提供了一些別的DOM操做的方法以下:
var box = document.getElementById('box');
box.firstChild.deleteData(0,2); //刪除從0位置的2個字符
box.firstChild.insertData(0,'Hello.'); //從0位置添加指定字符
box.firstChild.replaceData(0,2,'Miss'); //從0位置替換掉2個指定字符
box.firstChild.substringData(0,2); //從0位置獲取2個字符,直接輸出
alert(box.firstChild.nodeValue); //輸出結果
5.Comment類型
Comment類型表示文檔中的註釋。nodeType是8,nodeName是#comment,nodeValue是註釋的內容。
示例:<div id="box"><!--我是註釋--></div>
var box = document.getElementById('box');
alert(box.firstChild); //Comment
PS:在IE中,註釋節點可使用!看成元素來訪問。
var comment = document.getElementsByTagName('!');
alert(comment.length);
6.Attr類型
Attr類型表示文檔元素中的屬性。nodeType爲11,nodeName爲屬性名,nodeValue爲屬性值。(詳見DOM基礎篇)。
二.DOM擴展
1.呈現模式
從IE6開始開始區分標準模式和混雜模式(怪異模式),主要是看文檔的聲明。IE爲document對象添加了一個名爲compatMode屬性,這個屬性能夠識別IE瀏覽器的文檔處於什麼模式若是是標準模式,則返回CSS1Compat,若是是混雜模式則返回BackCompat。
if (document.compatMode == 'CSS1Compat') {
alert(document.documentElement.clientWidth);
} else {
alert(document.body.clientWidth);
}
PS:後來Firefox、Opera和Chrome都實現了這個屬性。從IE8後,又引入documentMode新屬性,由於IE8有3種呈現模式分別爲標準模式8,仿真模式7,混雜模式5。因此若是想測試IE8的標準模式,就判斷document.documentMode > 7 便可。
2.滾動
DOM提供了一些滾動頁面的方法,以下:
document.getElementById('box').scrollIntoView(); //將指定的節點滾動到可見範圍內
3.children屬性(DOM基礎篇)
因爲子節點空白問題,IE和其餘瀏覽器解釋不一致。雖然能夠過濾掉(詳見DOM基礎篇),但若是隻是想獲得有效子節點,可使用children屬性,支持的瀏覽器爲:IE5+、Firefox3.5+、Safari2+、Opera8+和Chrome,這個屬性是非標準的。
var box = document.getElementById('box');
alert(box.children.length); //獲得有效子節點數目
4.contains()方法
判斷一個節點是否是另外一個節點的後代,咱們可使用contains()方法。這個方法是IE率先使用的,開發人員無須遍歷便可獲取此信息。
var box = document.getElementById('box');
alert(box.contains(box.firstChild)); //true
PS:早期的Firefox不支持這個方法,新版的支持了,其餘瀏覽器也都支持,Safari2.x瀏覽器支持的有問題,沒法使用。因此,必須作兼容。
在Firefox的DOM3級實現中提供了一個替代的方法compareDocumentPosition()方法。這個方法肯定兩個節點之間的關係。
var box = document.getElementById('box');
alert(box.compareDocumentPosition(box.firstChild)); //20(下表4 + 16)
PS:爲何會出現20,那是由於知足了4和16兩項,最後相加了。
關係掩碼錶
掩碼 |
節點關係 |
1 |
無關(節點不存在) |
2 |
居前(節點在參考點以前) |
4 |
居後(節點在參考點以後) |
8 |
包含(節點是參考點的祖先) |
16 |
被包含(節點是參考點的後代) |
爲了能讓全部瀏覽器均可以兼容,咱們必須寫一個兼容性的函數。代碼以下:
1 //判斷一個節點是否是另外一個節點的後代 2 3 //傳遞參考節點(父節點),和其餘節點(子節點) 4 5 function contains(refNode, otherNode) { 6 7 //判斷支持contains,而且非Safari3.0如下瀏覽器 8 9 if (typeof refNode.contains != 'undefined' && 10 11 !(BrowserDetect.browser == 'Safari' && BrowserDetect.version < 3)) { 12 13 return refNode.contains(otherNode); 14 15 //判斷支持compareDocumentPosition的瀏覽器,大於16就是包含 16 17 } else if (typeof refNode.compareDocumentPosition == 'function') { 18 19 return !!(refNode.compareDocumentPosition(otherNode) > 16); 20 21 } else { 22 23 //更低版本的瀏覽器上述兩個都不支持 24 25 //兼容方法是經過遞歸一個個獲取他的父節點是否存在 26 27 var node = otherNode.parentNode; 28 29 do { 30 31 if (node === refNode) { 32 33 return true; 34 35 } else { 36 37 node = node.parentNode; 38 39 } 40 41 } while (node != null); 42 43 } 44 45 return false; 46 47 }
三.DOM操做內容
雖然在以前咱們已經學習了各類DOM操做的方法,這裏所介紹是innerText、innerHTML、outerText和outerHTML等屬性。除了以前用過的innerHTML以外,其餘三個還麼有涉及到(其實,其餘3個並不經常使用也不建議使用!)。
1.innerText屬性
document.getElementById('box').innerText; //獲取文本內容(若有html直接刪掉)
document.getElementById('box').innerText = 'Mr.Wang; //設置文本(若有html轉義)
PS:除了Firefox以外,其餘瀏覽器均支持這個方法。但Firefox的DOM3級提供了另一個相似的屬性:textContent,作上兼容便可通用。
document.getElementById('box').textContent; //Firefox支持
1 //兼容方案 2 3 function getInnerText(element) { 4 5 return (typeof element.textContent == 'string') ? 6 7 element.textContent : element.innerText; 8 9 } 10 11 12 13 function setInnerText(element, text) { 14 15 if (typeof element.textContent == 'string') { 16 17 element.textContent = text; 18 19 } else { 20 21 element.innerText = text; 22 23 } 24 25 }
2.innerHTML屬性(重點)
這個屬性以前就已經研究過,不拒絕HTML。
document.getElementById('box').innerHTML; //獲取文本(不過濾HTML)
document.getElementById('box').innerHTML = '<b>123</b>'; //可解析HTML
雖然innerHTML能夠插入HTML,但自己仍是有必定的限制,也就是所謂的做用域元素,離開這個做用域就無效了。以下:
box.innerHTML = "<script>alert('Wang');</script>"; //<script>元素不能被執行
3.outerText
outerText在取值的時候和innerText同樣,同時火狐不支持,而賦值方法至關危險,他不單替換了文本內容,還將元素直接抹去。
var box = document.getElementById('box');
box.outerText = '<b>123</b>';
alert(document.getElementById('box')); //null,建議不去使用
4.outerHTML
outerHTML屬性在取值和innerHTML一致,但和outerText也同樣,賦值的以後會將元素抹去,很危險。
var box = document.getElementById('box');
box.outerHTML = '123';
alert(document.getElementById('box')); //null,建議不去使用
關於最經常使用的innerHTML屬性和節點操做方法的比較,在插入大量HTML標記時使用innerHTML的效率明顯要高不少。由於在設置innerHTML時,會建立一個HTML解析器。這個解析器是瀏覽器級別的(C++編寫),所以執行JavaScript會快的多。但,建立和銷燬HTML解析器也會帶來性能損失。最好控制在最合理的範圍內,以下:
for (var i = 0; i < 10; i ++) {
ul.innerHTML = '<li>item</li>'; //避免頻繁
}
//改
for (var i = 0; i < 10; i ++) {
//臨時保存(建立中間臨時變量,這是JS經常使用性能優化方法之一)
a = '<li>item</li>';
}
ul.innerHTML = a;
很是感謝李老師~