DOM部分擴展

對DOM的兩個主要擴展是Selectors API和HTML5。javascript

選擇符API

Selectors API致力於讓瀏覽器原生支持CSS查詢。在沒有原生支持以前,只能經過javascript代碼來完成查詢操做。以後,解析和樹查詢操做能夠在瀏覽器內部經過編譯後的代碼來完成,極大地改善了性能。java

querySelector()方法

querySelector()方法接收一個CSS選擇符,返回與該模式匹配的第一個元素,若是沒有找到匹配的元素,返回null。node

經過Document類型調用時,會在文檔元素的範圍內查找匹配的元素。而經過Element類型調用時,只會在該元素後代元素的範圍內查找匹配的元素。web

<ul>
    <li class='one'></li>
    <li></li>
    <li></li>
</ul>

$ul = document.querySelector('ul');

$ul.querySelector('.one')
// return <li class='one'></li>
複製代碼

querySelectorAll()方法

querySelectorAll()方法接收的參數與querySelector()方法同樣,都是一個CSS選擇符,但返回的時全部匹配的元素。這個方法返回的時一個Nodelist實例。瀏覽器

<ul>
    <li class='one'></li>
    <li></li>
    <li></li>
</ul>

$ul = document.querySelector('ul');

$ul.querySelectorAll('.two')
// NodeList[]
複製代碼

能夠調用上面兩種方法的node類型包括:document、element、DocumentFragment。安全

matchesSelector()方法

Element類型新增了一個方法matchesSelector()。這個方法接收了一個參數,即CSS選擇符,若是調用元素與該選擇符匹配,返回true;不然,返回false。bash

這個方法尚未被全部瀏覽器都支持。app

元素遍歷

專門用於element類型的元素遍歷dom

  • childElementCount
  • firstElementChild
  • lastElementChild
  • perviousElementSibling
  • nextElementSibling

HTML5

HTML5規範則圍繞如何使用新增標記定義了大量Javascript API。其中一些API和DOM重疊,定義了瀏覽器應該支持的DOM擴展。函數

與類相關的擴充

getElementsByClassName()方法

這個方法能夠經過document對象以及全部HTML元素調用。

classList屬性

在操做類名時,須要經過className屬性添加、刪除和替換類名。由於className中是一個字符串,因此即便只修改字符串的一部分,也必須每次都設置整個字符串的值。

<div class='a b c'></div>
var className = div.className.split(/\s+/);
var pos = -1;
var i;
var len;
for (i=0, len=className.length; i < len; i++) {
    if (className[i] == 'a') {
        pos = i;
        break;
    }
}

//刪除類名
className.splice(i, 1)

//把剩下的類名拼成字符串並從新設置
div.className = className.join(' ');
複製代碼

HTML5新增了一種操做類名的方式,可讓操做更簡單也更安全,那就是爲全部元素添加classList屬性。這個classList屬性是新集合類型DOMTokenList的實例。
DOMTokenList有一個表示本身包含多少元素的length屬性,而要取得每一個元素可使用item()方法,也可使用方括號語法。此外這個新類型還定義以下方法。

  • add(value): 將給定的字符串值添加到列表中。若是值已經存在,就不添加了。
  • contains(value): 表示列表中是否存在給定的值,若是存在則返回true,不然返回false。
  • remove(value): 從列表中刪除給定的字符串
  • toggle(value): 若是列表中已經存在給定的值,刪除它;若是列表中沒有給定的值,添加它。

焦點管理

document.activeElement屬性,這個屬性始終引用了DOM中當前得到了焦點的元素。元素得到焦點的方式有頁面加載、用戶輸入和在代碼中調用focus()方法。

var dom = document.getElementById('dom');

dom.focus();

document.activeElement === dom;  // true
dom.hasFocus();  // true
複製代碼

HTMLDocument變化

添加readyState屬性

Document的readyState屬性有兩個可能的值:

  • loading,正在加載文檔
  • complete,已經加載文檔 document.readyState屬性的基本用法以下:
if(document.readyState === 'complete') {
    // 執行操做
}
複製代碼

head屬性

新增document.body方法,直接引用元素

字符集屬性

HTML5新增了幾個與文檔字符集有關的屬性。其中,charset屬性表示文檔中實際使用的字符集,也能夠用來指定新字符集。

自定義數據屬性

HTML5規定能夠爲元素添加非標準的屬性,但要添加前綴data-。

var dom = `<div id='myDiv' data-appid='234' data-myname='zc'></div>`;
var $container = document.createElement('div');
$container.innerHTML = dom;
var $dom = $container.firstElementChild;

$dom.dataset; // DOMStringMap {appid: "234", myname: "zc"}

$dom.dataset.appid = 12;

$dom.dataset; // DOMStringMap {appid: "12", myname: "zc"}
複製代碼

插入標記

使用插入標記的技術,直接插入HTML字符串不只更簡單,速度也更快。如下與插入標記相關的DOM擴展已經歸入了HTML5規範。

innerHTML屬性

在讀模式下,innerHTML屬性返回與調用元素的全部子節點(包括元素、註釋和文本節點)對應的HTML標記。在寫模式下,innerHTML會根據指定的值建立新的DOM樹,而後用這個DOM樹徹底替換調用元素原先的全部子節點。

可是,不一樣瀏覽器返回的文本格式會有所不一樣。IE和Opera會將全部標籤轉換成大寫形式。而Safari、Chrome和Firefox則會原本來本地按照原先文檔中的格式指定返回HTML,包括空格和縮進。

在寫模式下,innerHTML的值會被解析爲DOM子樹,替換調用元素原來的全部子節點。由於它的值被認爲是HTML,因此其中的全部標籤都會按照瀏覽器處理HTML的標準方式轉換爲元素。

爲innerHTML設置HTML字符串後,瀏覽器會將這個字符串解析爲相應的DOM樹。所以設置了innerHTML以後,再從中讀取HTML字符串,會獲得與設置時不同的結果。緣由在於返回的字符串是根據原始HTML字符串建立的DOM樹通過序列化以後的結果。

outerHTML屬性

在讀模式下,outerHTML返回調用它的元素及全部子節點的HTML標籤。在寫模式下,outerHTML會根據指定的HTML字符串建立新的DOM子樹,而後用這個DOM子樹徹底替換調用元素。

insertAdjacentHTML()方法

插入標記的最後一個新增方式是insertAdjacentHTML()方法。這個方法最先也是在IE中出現的,它接受兩個參數:插入位置和要插入的HTML文本。第一個參數必須是下列值之一:

  • beforeBegin,在當前元素以前插入一個緊鄰的同輩元素

內存與性能問題

使用本節介紹的方法替換子節點可能會致使瀏覽器的內存佔用問題,尤爲在IE中,問題更加明顯。在刪除帶有事件處理程序或引用了其餘Javascript對象子樹時,就有可能致使內存佔用問題。假設某個元素有一個事件處理程序(或者引用了一個javascript對象做爲屬性),在使用前述某個屬性將該元素從文檔樹中刪除後,元素與事件處理程序(javascript對象)之間的綁定關係在內存中並無一併刪除。若是這種狀況頻繁出現,頁面佔用的內存數量就會明顯增長。所以,在使用innerHTML、outerHTML、insertAdjacentHTML()方法時,最好先手工刪除要被替換的元素的全部事件處理程序和Javascript對象屬性。

同理: 每次循環都設置一次innerHTML的作法效率很低。

for (var i = 0; len = values.length; i < len; i++) {
    ul.innerHTML += "<li>" + values[i] + "</li>";  // 要避免這種頻繁操做
}
複製代碼

效率更高的:

for (var i = 0, len = values.length; i <len; i++) {
    itemsHtml += "<li>" + values[i] + "</li>";
}

ul.innerHTML = itemsHTML;
複製代碼

那些沒有標準化的專用擴展

文檔模式

IE8引入了一個新的概念叫作「文檔模式」(document mode)。頁面的文檔模式決定了可使用什麼功能。換句話說,文檔模式決定了你可使用哪一個級別的CSS,能夠在JavaScript中使用哪些API,以及如何對待文檔類型(doctype)。到了IE9,總共有如下4種文檔模式。

  • IE5: 以混雜模式渲染頁面。
  • IE7: 以IE7標準模式渲染頁面。IE8及更高版本中的新功能都沒法使用。
  • IE8: 以IE8標準模式渲染頁面。IE8中的新功能均可以使用,所以可使用Selectors API、更多CSS2選擇符和某些CSS3功能,還有一些HTML5的功能。不過IE9中的新功能沒法使用。
  • IE9:以IE9標準模式渲染頁面。IE9中的新功能均可以使用,好比ECMAScript五、完整的CSS3以及更多HTML5功能。這種文檔模式是最高級的模式。
<meta http-equiv='X-UA-Compatible' content='IE=IEVersion'>
複製代碼

The http-equiv attribute is used by servers to gather information about a page using the HTTP header. The meta tag’s http-equiv attribute set is similar to a http header.

children屬性

這個屬性是HTMLCollection的實例,只包含元素中一樣仍是元素的子節點。除此以外,children屬性與childNodes沒有什麼區別。即在元素只包含元素子節點時,這兩個屬性的值相同。

contains方法

在實際開發中,常常須要知道某個節點是否是另外一個節點的後代。IE爲此率先引入了contains()方法,以便不經過在DOM文檔樹中查找便可得到這個信息。調用contains()方法的應該是祖先節點,也就是搜索開始的節點,這個方法接收一個參數,即要檢測的後代節點。若是被檢測的節點是後代節點,該方法返回true;不然,返回false。

document.documentElement.contains(document.body);   // true
複製代碼

使用DOM Level3 compareDocumentPosition()也可以肯定節點間的關係。這個方法用於肯定兩個節點間的關係,返回一個表示關係的位掩碼。

function contains (refNode, otherNode) {
    if (typeof refNode.contains == 'function' && (!client.engine.webkit || client.engine.webkit >= 522)) {
 return refNode.contains(otherNode);
    } else if (typeof refNode.compareDocumentPosition == "function") {
        return !!(refNode.compareDocumentPosition(otherNode) & 16);
    } else {
        var node = otherNode.parentNode;
        do {
            if(node === refNode) {
                return true;
            }
            node = node.parentNode;
        } while (node !== null);
        return false;
    }
}
複製代碼

插入文本

前面介紹過,IE原來專有的插入標記的屬性innerHTML和outerHTML已經被HTML5歸入規範。但另外兩個插入文本的專有屬性則沒有這麼好的運氣。這兩個沒有被HTML5看中的屬性是innerText和outerText。

innerText屬性

經過innerText屬性能夠操做元素中包含的全部文本內容,包括子文檔樹中的文本。在經過innerText讀取值時,它會按照由淺入深的順序,將子文檔樹中的全部文本拼接起來。在經過innerText寫入值時,結果會刪除元素的全部子節點,插入包含相應文本值的文本節點。
支持innerText屬性的瀏覽器包括IE4+、safari 3+、Opera 8+和Chrome。Firefox雖然不支持innerText,但支持做用相似的textContent屬性。textContent是DOM Level3規定的一個屬性。爲了確保跨瀏覽器兼容,有必要編寫一個相似於下面的函數來檢測可使用哪一個屬性。

function getInnerText (element) {
    return (typeof element.textContent == 'string') ? element.textContent : element.innerText;
}

function setInnerText (element, text) {
    if (typeof element.textContent == 'string') {
        element.textContent = text;
    } else {
        element.innerText = text;
    }
}
複製代碼

outerText屬性

除了做用範圍擴大到了包含調用它的節點以外,outerText與innerText基本上沒有多大區別。

div.outerText = 'Hello World';
// 這行代碼實際上至關於以下兩行代碼
var text = document.createTextNode('Hello World');

div.parentNode.replaceChild(text, div)
複製代碼

滾動

HTML5以前的規範並無就與頁面滾動相關的API作出相關規定。但HTML5在將scrollIntoView()歸入規範以後,仍然還有其餘幾個專有方法能夠在不一樣的瀏覽器中使用。下面列出的幾個方法都是對HTMLElement類型的擴展,所以在全部元素中均可以調用。

小結

本章主要介紹了一些DOM擴展:

  • Selectors API,定義了兩個方法,讓開發人員可以基於CSS選擇符從DOM中取得元素,這兩個方法是querySelector()和querySelectorAll()。
  • Element Traversal,爲DOM元素定義了額外的屬性,讓開發人員可以更方便地從從一個元素跳到另外一個元素。之因此會出現這個擴展,是由於瀏覽器處理DOM元素間空白符的方式不同。
  • HTML5,爲標準的DOM定義了不少擴展功能。
  • 等等
相關文章
相關標籤/搜索