這次總結的是剩下的這些DOM類型節點,可能你見過卻不經常使用但是瞭解一下總是好的,可以加深對DOM體系的整體理解~。本篇要介紹的是Comment,CDATASection,DocumentType,DocumentFragment,Attr類型。Comment類型 原型鏈繼承關係為comment實例 ...
這次總結的是剩下的這些DOM類型節點,可能你見過卻不經常使用但是瞭解一下總是好的,可以加深對DOM體系的整體理解~。本篇要介紹的是Comment,CDATASection,DocumentType,DocumentFragment,Attr類型。
Comment類型
原型鏈繼承關係為comment實例.__proto__->Comment.prototype->CharacterData.prototype->Node.prototype->EventTarget.prototype->Object.prototype。
與Text節點類似,也可以通過nodeValue或data訪問註釋的內容。
var com=document.createComment('I am comment'); com;// <!--I am comment--> com.data;// "I am comment" com.nodeValue;// "I am comment"
註釋在DOM中通過Comment類型來表示的,Comment節點具有以下特征:
- nodeType值為8
- nodeName值為"#comment"
- nodeValue值是註釋內容
- parentNode可能為Document或Element
- 沒有子節點
1.使用document.createComment()併為其傳遞註釋文本可創建註釋節點。createComment繼承自Document.prototype。
2.瀏覽器對於註釋節點的處理有些差距
(1).當註釋位於HTML元素外 :Chrome,<=IE9處理HTML元素之前的註釋節點,FF和>IE9 處理之外的所有節點。
<!--I am first comment--> <!DOCTYPE html> <html> <head> <title></title> </head> <body> </body> </html> <!--I am last comment-->
Chrome46.0.2490.80:只處理出現在HTML元素之前的的註釋節點,忽略出現在HTML元素之後的註釋節點。
FF44.0.2:出現在HTML元素之前之後的註釋節點都會處理。
>IE9:出現在HTML元素之前之後的註釋節點都會處理。
<=IE9:只處理HTML元素之前的註釋節點。
註意:IE8中註釋節點和文檔聲明被當作標簽名為"!"的元素,開啟IE8模擬模式後,由於IE8不支持訪問DOM中一些API原生對象,所以通過使用getElementsByTagName()(繼承自Document.prototype)可以取得被當作元素節點的註釋節點和文檔聲明節點。
IE9沒有把註釋和文檔聲明當成元素節點,但卻將文檔聲明節點<!Doctype html>視作註釋節點。本圖測試於IE9模擬
(2).當註釋位於HTML元素內
<!DOCTYPE html> <html> <head> <title></title> <!-- I am comment--> </head> <body> <!-- I am comment too--> </body> </html>
三大瀏覽器均能解釋成註釋節點。
CDATASection類型
- 瞭解XHTML
說起CDATASection類型節點,就先說起XHTML(可擴展超文本標記語言),它是將HTML作為XML的應用而重新定義的一個標準,編寫XHTML代碼的規則要比HTML嚴格很多,比如
- XHTML元素必須被正確嵌套
- XHTML元素必須被正確關閉,即使是空標簽也必須被正確關閉比如<br />,<img />,註意/與元素之間留有空格保證XHTML文檔與當今瀏覽器相容
- 標簽名必須用小寫字母
- XHTML文檔必須擁有根元素
- 屬性值必須加引號
- 屬性不能簡寫
- 用id屬性代替name屬性,如<a />,<img />等
- XHTML DTD定義了強制使用的HTML元素
- 所有XHTML文檔必須進行文檔類型聲明。
以下麵代碼塊為例,它們在HTML中是有效的,但是在XHTML中是無效的
<script type="text/javascript"> function compare(a, b){ if(a < b){ console.log("A is less than B"); }else if(a > b){ console.log("A is greater than B"); }else{ console.log("A is equal to B"); } } </script>
在HTML中有特殊規則用以確定<script>元素中哪些內容可以被解析,但這些規則在XHTML中不適用。這裡比較語句a < b的小於號在XHTML中將被當作開始一個新標簽來解析,但作為標簽來說小於號後面又不能跟空格,因此就會導致語法錯誤如下“不合法的元素名”,所以JS代碼後面就解析不了原樣顯示在頁面上。
即使將代碼中a < b間的空格去掉變為a<b,也會提示出錯“解析屬性出錯”,畢竟b後面跟的是“)”。
避免出現這種情況的解決方式有兩種:
(1).應用相應的HTML實體(<),替換代碼中所有的小於號(<),替換後一切正常
(2).用一個CData片段來包含JS代碼,因為在XHTML(XML)中CData片段是文檔中一個特殊區域,這個區域可以包含不需要解析的任意格式的文本內容。很明顯CDATA被解析為了一個節點。
<script type="text/javascript"><![CDATA[ function compare(a, b){ if(a < b){ console.log("A is less than B"); }esle if(a > b){ console.log("A is greater than B"); }else{ console.log("A is equal to B"); } } ]]></script>
在相容XHTML的瀏覽器中這個辦法可行,但實際上還有不少瀏覽器不相容XHTML因而不支持CData片段。這種情況下使用JS註釋將CData標記註釋掉就可。
<script type="text/javascript"> //<![[ function compare(a, b){ if(a < b){ }else if(a >b){ }else{ } } //]]> </script>
- CDATASection類型
用JS也可以創建CData片段:
CDATASection只針對基於XML的文檔,表示的是CDATA區域,原型鏈的繼承關係為CDATASection實例.__proto__=>CDATASection.prototype=>Text.prototype=>CharacterData.prototype=>Node.protoype=>EventTarget.prototype。
CDATASection節點具有下列特征:
- nodeType值為4
- nodeName值為"cdata-section"
- nodeValue值是內容區域的內容
- parentNode可能是Document或Element
- 不支持子節點
(1).相容性:CDATA區域只會出現在XML/XHTML文檔中,對於HTML文檔會把CDATA區域錯誤地解析為註釋節點或過濾掉,>=IE10和FF和Chrome會解析為Comment類型節點。<IE10會忽略該節點,因為IE9之前的版本中不支持CDATASection類型。
(2).在真正XML文檔中,可以使用document.createCDATASection(text)創建CDATA區域,只需傳入節點內容即可。在HTML文檔上使用document.createCDATASection()會報錯說不支持HTML文檔。CDATA節點不能插入document節點中,只能插進標簽中。
var cd=document.createCDATASection('mycdata'); cd;// <![CDATA[mycdata]]> document.appendChild(cd);/*Uncaught DOMException: Failed to execute 'appendChild' on 'Node':
Nodes of type '#cdata-section' may not be inserted inside nodes of type '#document'.*/
CDATA區段不能進行嵌套,CDATA區段包含了不會被解析器解析的文本,CDATA中的標簽不會被視為標簽同時實體也不會被展開,主要目的是為了包含註入XML片段之類的材料,無需轉義所有分隔符。
DocumentType類型
DocumentType節點包含著與文檔的doctype有關的信息,原型鏈繼承關係為document.doctype.__proto__=>DocumentType.prototype=>Node.prototype=>EventTarget.prototype。
它具有下列特征:
- nodeType值為10
- nodeName值為doctype名稱,保存文檔類型的名稱即當前文檔最外層標簽頂級元素,document.doctype.name也可獲取,就是出現在<!DOCTYPE 之後的文本(不包括後面那些PUBLIC...DTD版本號和文件路徑)獲取的為小寫內容(不論之前代碼中是否大小寫)。這兩種方式都是不可寫的,因為nodeName和name的訪問器屬性set為undefiend。
註:有點疑問,經測試document.doctype只能在HTML文檔中獲取到DocumentType節點,在XML/XHTML中均為null(表明document.doctype是一個空指針)。
- nodeValue值為null
- parentNode是Document
- 沒有子節點
在DOM1級中,DocumentType對象不能動態創建,只能通過解析文檔代碼的方式創建,支持它的瀏覽器會把DocumentType對象保存在document.doctype中。DOM1級描述了DocumentType對象的三個屬性:name,entities,notations(它們都是DocumentType.prototype對象上的三個屬性,但Chrome中好像已經沒有後兩個屬性了,反正沒獲取到這兩個屬性)。
DocumentFragment類型
在所有節點類型中,只有DocumentFragment在文檔中沒有對應標記。原型鏈關係為: 文檔片段實例.__proto__=>DocumentFragment.prototype=>Node.prototype=>EventTarget.prototype
註意文檔片段類型只支持getElementById獲取元素,沒有getElementsByTagName那系列的,不過可以通過querySelector獲取,畢竟很萬能~
DOM規定文檔片段是一種輕量級的文檔,可以包含和控制節點,但不會像完整的文檔那樣占用額外的資源。DocumentFragment節點具有下列特征:
- nodeType值為11
- nodeName值為"#document-fragment"
- nodeValue值為null
- parentNode值為null
- 子節點可以是Element,ProcessingInstruction,Comment,Text,CDATASection,EntityReference
可以把文檔片段當作一個倉庫來使用,可以在裡面保存將來可能會添加到文檔中的節點。創建文檔片段使用document.createDocumentFragment()方法。
如果將文檔中本身存在的節點添加到文檔片段中,就會從文檔樹中移除該節點。
可以通過appendChild或insertBefore將文檔片段中內容添加到文檔中(其實還是繼承自Node.prototype那些方法),在將文檔片段作為參數傳遞給這兩個方法時,實際上只會將文檔片段的所有子節點添加到相應位置,文檔片段節點本身永遠不會成為文檔樹的一部分。假設想為ul元素添加三個列表項,如果逐個地添加列表項,將會導致瀏覽器反覆渲染新信息。我們可以將所有列表項加到文檔片段中,最後再一次性將它們添加到文檔中。
var df = document.createDocumentFragment(); var ul= document.createElement('ul'); var li=null; for(var i=0;i<3;i++){ li = document.createElement('li'); li.appendChild(document.createTextNode("Item"+(i+1))); df.appendChild(li); } ul.appendChild(df);
現在看ul和df元素,說明文檔片段節點並沒加到ul中去,而是它裡面的內容加進去了。
Attr類型
元素的特性在DOM中以Attr類型來表示,在除了<=IE7之外的所有瀏覽器都可以訪問Attr類型的構造函數和原型。特性節點就是一種對象,就是存在於元素的attributes屬性(繼承自Element.prototype)中的節點。某元素的attributes屬性指向的是一個NamedNodeMap類型的實例集合。在該集合中的每一項才是我們需要的屬性節點對象。
原型鏈繼承關係為:attrNode.__proto__=>Attr.prototype=>Node.prototype=>EventTarget.prototype
特性節點具有下列特征
- nodeType值為2
- nodename值是特性的名稱
- nodeValue值是特性的值
- parentNode值為null
- 在HTML中不支持子節點
- 在XML中子節點可以是Text或EntityReference
儘管特性節點也是節點,但卻不認為是DOM文檔樹中的一部分。開發人員最常使用的是getAttribute(),setAttribute(),removeAttribute()很少直接引用特性節點(這些方法繼承自Element.prototype)。
(1).Attr對象有三個屬性:name,value,specified
name :特性名稱,與nodeName值相同
value :特性的值,與nodevalue值相同
specified :是一個布爾值,用以區別特性是在代碼中指定的還是預設的
(2).創建新的特性節點:document.createAttribute()
當在調用createAttribute()時已經為name屬性賦了值,所以後面就不需要給它賦值,在將特性節點添加到元素中時必須使用setAttributeNode。添加後可以通過attributes,getAttributeNode,getAttribute方法訪問。不過不建議直接訪問特性節點,使用getAttribute,setAttribute,removeAttribute比操作特性節點方便多。
參考
《JavaScript高級程式設計》