This is a paragraph with a list following it.
- Item 1
- Item 2
- Item 3
摘要:對(duì)的兩個(gè)主要拓展是選擇和。以下插入標(biāo)記的拓展已經(jīng)納入了規(guī)范。在寫(xiě)模式下,會(huì)根據(jù)指定的字符串創(chuàng)建新的子樹(shù),然后用這個(gè)子樹(shù)完全替換調(diào)用元素。在刪除帶有時(shí)間處理程序或引用了其他對(duì)象子樹(shù)時(shí),就有可能導(dǎo)致內(nèi)存占用問(wèn)題。
盡管DOM作為API已經(jīng)非常完善了,但為了實(shí)現(xiàn)更多功能,仍然會(huì)有一些標(biāo)準(zhǔn)或?qū)S械耐卣埂?008年之前,瀏覽器中幾乎所有的拓展都是專有的,此后W3C著手將一些已經(jīng)成為事實(shí)標(biāo)準(zhǔn)的專有拓展標(biāo)準(zhǔn)化,并寫(xiě)入規(guī)范中。
對(duì)DOM的兩個(gè)主要拓展是Selectors API (選擇API)和HTML5。這兩個(gè)拓展都源自開(kāi)發(fā)社區(qū),而將某些常見(jiàn)做啊及API標(biāo)準(zhǔn)化,一直是眾望所歸。
選擇符APIjQuery的核心就是通過(guò)CSS選擇符查詢DOM文檔取得元素的引用,從而拋開(kāi)了getElementById() 和 gettElementByTagName()。
Selectors API 是又W3C發(fā)起制定的一個(gè)標(biāo)準(zhǔn),致力于讓瀏覽器原生支持CSS查詢。所有實(shí)現(xiàn)這一功能的JavaScript庫(kù)都會(huì)寫(xiě)一個(gè)基礎(chǔ)的CSS解析器,然后再使用已有的DOM方法查詢文檔并找到匹配的節(jié)點(diǎn)。而把這個(gè)功能變成原生API之后,解析和樹(shù)查詢操作可以在瀏覽器內(nèi)部通過(guò)編譯后的代碼完成,極大改善了性能。
querySelector()方法querySelector()方法接收一個(gè)CSS選擇符,返回與該模式匹配的第一個(gè)元素,如果沒(méi)有找到匹配的元素,返回null。
// 取得body元素 var body = document.querySelector("body"); // 取得ID為“myDiv”的元素 var myDiv = document.querySelector("#myDiv"); // 取得類為"selected"的第一個(gè)元素 var selected = document.querySelector(".selected"); // 取得類為"button"的第一個(gè)圖像元素 var selected = document.querySelector("img.button");
如果傳入了不支持的選擇符,會(huì)拋出錯(cuò)誤。
querySelectorAll()方法和上面類似,但返回的不僅僅是匹配的第一個(gè)元素,而是一個(gè)NodeList的實(shí)例,如果沒(méi)有匹配,NodeList就是空的。
// 取得某div中所有em元素 var ems = document.getElementById("myDiv").querySelectorAll("em"); // 取得類為“selected”的所有元素 var selected = document.querySelectorAll(".selected"); // 取得所有p元素中的所有strong元素 var strongs = document.querySelectorAll("p strong");
取得返回NodeList中的每一個(gè)元素,可以使用item()方法,也可以使用方括號(hào)語(yǔ)法。
matchesSelector()方法Selector API Level2 規(guī)范為Element類型新增了一個(gè)matchesSelector()方法。接收一個(gè)參數(shù),即CSS選擇符,如果調(diào)用元素與該選擇符匹配返回true,否則返回false。
截止2011年年中,還沒(méi)有瀏覽器支持該方法,不過(guò)有一些實(shí)驗(yàn)性的實(shí)現(xiàn)。因此如果你想使用這個(gè)方法,最好編寫(xiě)一個(gè)包裝函數(shù):
function matchesSelector(element, selector) { if (element.matchesSelecotr) { return element.matchesSelecotr(selector) } else if (element.msMatchesSelecotr) { return element.msMatchesSelecotr(selector) } else if (element.mozMatchesSelecotr) { return element.mozMatchesSelecotr(selector) } else if (element.webkitMatchesSelecotr) { return element.webkitMatchesSelecotr(selector) } else { throw new Error("Not supported."); } }元素遍歷
對(duì)于元素間的空格,IE9及之前版本不會(huì)返回文本節(jié)點(diǎn),而其他所有瀏覽器都會(huì)返回文本節(jié)點(diǎn)。為了彌補(bǔ)這一差異,而又同時(shí)保持DOM規(guī)范不變,Element Traversal 規(guī)范新定義了一組屬性。
childElementCount: 返回子元素(不包括文本節(jié)點(diǎn)和注釋)的個(gè)數(shù)
firstElementChild: 指向第一個(gè)子元素;firstChild的元素版
lastElementChild: 指向最后一個(gè)子元素;lastChild的元素版
previousElementSibling: 指向前一個(gè)同輩元素;previousSibling的元素版
nextElementSibling: 指向前一個(gè)同輩元素;nextSibling的元素版
// 跨瀏覽器遍歷某元素的所有子元素 // 老版的兼容性代碼 var i, len, child = element.firstChild; while(child != element.lastChild) { // 檢查是不是元素 if (child.nodeType == 1) { processChild(child); } child = child.nextSibling; } // 使用新版的方法 var i, len, child = element.firstChild; while(child != element.lastElementChild) { processChild(child); child = child.nextElementSibling; }
支持Element Traversal 規(guī)范的瀏覽器有 IE9+ Firefox3.5+ Safari4+ Chrome Opera10+
HTML5HTML5所有之前的版本對(duì)JavaScript接口的描述不過(guò)三言兩語(yǔ),主要篇幅都用于定義標(biāo)記,與JavaScript相關(guān)的內(nèi)容一概交由DOM規(guī)范去定義。
HTML5規(guī)范則圍繞如何使用新增標(biāo)記定義了大量JavaScript API。其中一些API與DOM重疊,定義了瀏覽器應(yīng)該支持的DOM拓展。
由于HTML5涉及的面非常廣,本節(jié)只討論與DOM節(jié)點(diǎn)相關(guān)的內(nèi)容。
與類(class)相關(guān)的擴(kuò)充HTML5 新增了很多API,致力于簡(jiǎn)化CSS類的用法。
getElementsByClassName()方法// 取得所有類中包含"username"和"current"的元素 // 類名的先后順序無(wú)所謂 var allCurrentUsernames = docment.getElementsByClassName("username current"); // 取得ID為"myDiv"的元素中帶有類名"selected"的所有元素 var selected = document.getElementById("myDiv").getElemenstByClassName("selected");
支持getElementsByClassName()方法的瀏覽器 IE9+ Firefox3+ Safari3.1+ Chrome Opera9.5+
classList屬性在操作類名時(shí),需要通過(guò)className屬性添加、刪除和替換類名。因?yàn)?b>className中是一個(gè)字符串,所以即使只是修改字符串一部分,也必須每次都設(shè)置整個(gè)字符串的值。
HTML5 新增了一種操作類名的方式,可以讓操作更簡(jiǎn)單也更安全,那就是為所有元素添加了classList屬性。
classList屬性是新集合類型 DOMTokenList的實(shí)例。與其他DOM集合類似,DOMTokenList 有一個(gè)表示自己包含多少元素的length屬性,而要去的每個(gè)元素可以使用item()方法,或者方括號(hào)語(yǔ)法。此外,這個(gè)新類型還定義如下方法:
add(value): 將給定的字符串值添加到列表中。如果值已經(jīng)存在,就不添加了。
contains(value): 表示列表中是否存在給定的值,如果存在返回true,反之false。
remove(value): 從列表中刪除給定的字符串。
toggle(value): 如果列表中已經(jīng)存在給定的值,刪除它;如果沒(méi)有,添加它。
有了classList屬性,除非你需要?jiǎng)h除所有類名,或者完全重寫(xiě)元素的class屬性,否則就用不到className屬性了。
支持classList的瀏覽器 Firefox3.6+ Chrome
焦點(diǎn)管理HTML5添加了輔助DOM焦點(diǎn)的功能。
document.activeElement屬性,始終會(huì)引用DOM中當(dāng)前獲得了焦點(diǎn)的元素。元素獲得焦點(diǎn)的方式有頁(yè)面加載、用戶輸入(通常是通過(guò)Tab鍵)和在代碼中調(diào)用focus()方法。
var button = document.getElementById("myButton"); button.focus(); console.log(document.activeElement === button); // true
默認(rèn)情況下,文檔剛剛加載完成時(shí),document.activeElement中保存的是document.body元素的引用。文檔加載期間,document.activeElement的值為null
document.hasFocus()方法,這個(gè)方法用于確定文檔是否獲得了焦點(diǎn)。
var button = document.getElementById("myButton"); button.focus(); console.log(document.hasFocus()); // true
支持的瀏覽器 IE4+ Firefox3+ Safari4+ Chrome Opera8+
HTMLDocument的變化 readyState屬性
Document.readyState屬性有兩個(gè)可能的值:
loading正在加載文檔
complete已經(jīng)加載完文檔
支持的瀏覽器 IE4+ Firefox3.6+ Safari Chrome Opera9+
if (document.readyState == "complete") { ... }兼容模式
自從IE6開(kāi)始區(qū)分渲染頁(yè)面的模式是標(biāo)準(zhǔn)的還是混雜的,檢測(cè)頁(yè)面的兼容性就成為瀏覽器的必要功能。IE為此給document添加了一個(gè)名為compatMode的屬性,告訴開(kāi)發(fā)人員瀏覽器采用了哪種渲染模式。
document.compatMode標(biāo)準(zhǔn)模式下等于"CSS1Compat",混雜模式下等于"BackCompat"。
最終HTML5將這個(gè)屬性納入標(biāo)準(zhǔn)
支持的瀏覽器 IE Firefox Safari3.1 Chrome Opera
if (document.compatMode == "CSS1Compat") { console.log("Standards mode"); } else { console.log("Quirks mode"); }head屬性
HTML5新增了document.head屬性,與docuemnt.body對(duì)應(yīng)
支持的瀏覽器 Chrome Safari 5+
var head = document.head || document.getElementsByTagName("head")[0];字符集屬性
HTML5新增了幾個(gè)與文檔字符集有關(guān)的屬性
charset屬性表示文檔中實(shí)際使用的字符集,也可以用來(lái)指定新字符集。默認(rèn)值是"UTF-16",可以通過(guò)元素、響應(yīng)頭部或直接設(shè)置charset屬性修改這個(gè)值。
支持的瀏覽器 IE Safari Opera Chrome 。 Firefox 支持 document.Characterset。
console.log(document.charset); // "UTF-16" document.charset = "UTF-8";
defaultCharset表示根據(jù)默認(rèn)瀏覽器及操作系統(tǒng)的設(shè)置,當(dāng)前文檔默認(rèn)的字符集應(yīng)該是什么。如果文檔沒(méi)有使用默認(rèn)的字符集,那charset和defaultCharset屬性值可能會(huì)不一樣。
if (document.charset != document.defaultCharset) { console.log("Custom character set being used."); }
支持的瀏覽器 IE Safari Chrome 。
自定義數(shù)據(jù)屬性HTML5 規(guī)定可以為元素添加非標(biāo)準(zhǔn)的屬性,但要添加前綴data- ,目的是為元素提供與渲染無(wú)關(guān)的信息,或者提供語(yǔ)義信息。這些屬性可以任意添加、隨便明明,只要以data-開(kāi)頭即可。
添加了自定義屬性之后,可以通過(guò)元素的dataset屬性來(lái)訪問(wèn)自定義屬性的值。dataset屬性的值時(shí)DOMStringMap的實(shí)例,也就是一個(gè)名值對(duì)的映射。在這個(gè)映射中,每個(gè)data-name形式的屬性都會(huì)有一個(gè)對(duì)應(yīng)的屬性,只不過(guò)屬性沒(méi)有data-前綴。
var div = document.getElementById("myDiv"); // 取得自定義屬性的值 var appId = div.dataset.appId; var myName = div.dataset.myname; // 設(shè)置值 div.dataset.appId = 2345; div.dataset.myname = "Michael"; // 有沒(méi)有"myname"值呢? if (div.dataset.myname) { console.log("Hello, " + div.dataset.myname); }插入標(biāo)記
雖然DOM為操作節(jié)點(diǎn)提供了細(xì)致入微的控制手段,但在需要給文檔插入大量HTML標(biāo)記的情況下,通過(guò)DOM操作仍然非常麻煩,因?yàn)椴粌H要?jiǎng)?chuàng)建一系列DOM節(jié)點(diǎn),還要小心按照正確的順序把它們連接起來(lái)。
相對(duì)而言,直接插入HTML字符串不僅更簡(jiǎn)單,速度也更快。以下插入標(biāo)記的DOM拓展已經(jīng)納入了HTML5規(guī)范。
innerHTML屬性在讀模式下,innerHTML屬性返回與調(diào)用元素的所有子節(jié)點(diǎn)(包括元素、注釋和文本節(jié)點(diǎn))對(duì)應(yīng)的HTML標(biāo)記。
在寫(xiě)模式下,innerHTML會(huì)根據(jù)指定的值創(chuàng)建新的DOM樹(shù),然后用這個(gè)DOM樹(shù)完全替換調(diào)用元素原先的所有子節(jié)點(diǎn)。
This is a paragraph with a list following it.
- Item 1
- Item 2
- Item 3
This is a paragraph with a list following it.
不同瀏覽器返回的文本格式不會(huì)有所不同。IE和Opera會(huì)將所有標(biāo)簽轉(zhuǎn)換為大小寫(xiě)形式,而Safari、Chrome、Firefox則會(huì)原原本本的按照原先文檔中(或指定這些標(biāo)簽時(shí))的格式返回HTML,包括空格和縮進(jìn)。
在寫(xiě)模式下,傳入innerHTML的值都會(huì)按照瀏覽器處理HTML的標(biāo)注方式轉(zhuǎn)換為元素(同樣因?yàn)g覽器而異)。如果設(shè)置的值僅是純文本而沒(méi)有HTML標(biāo)簽,那么結(jié)果就是設(shè)置純文本。
div.innerHTML = "Hello world!"; div.innerHTML = "Hello & welcom, "reader"!"; // 以上操作得到:Hello & welcome, "reader"!
使用innerHTML屬性也有一些限制,大多數(shù)瀏覽器中通過(guò)innerHTML插入