DOM擴充套件

hzbje7XSXP發表於2017-03-02

儘管DOM作為API已經非常完善了,但是為了實現更多的功能,仍然會有一些標準或專有的擴充套件。對DOM的兩個主要擴充套件是Selectors API(選擇符API)和HTML5

一、選擇符API

Selectors API是由W3C發起制定的一個標準,致力於讓瀏覽器原生支援CSS查詢。其核心的兩個方法:querySelector()querySelectorAll()

1. querySelector()方法

querySelector()接受一個CSS選擇符,返回與該模式匹配的第一個元素,如果沒有找到匹配的元素返回null。 
示例

document.querySelector("body");
document.querySelector("#content");
document.querySelector(".bd");
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

2. querySelectorAll()方法

querySelectorAll()接受一個CSS選擇符,返回與該模式匹配的NodeList例項,如果沒有找到匹配的元素返回null。 
示例

var lis = document.querySelectorAll("ul li");
// 獲取第一個li
lis.item(0); // 等價於:lis[0];
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

注意:上述兩個函式如果傳入不支援的選擇符,會丟擲錯誤。

3. matchesSelector()方法

matchesSelector()方法大部分瀏覽器未實現,可使用matches()或者使用各個瀏覽器實驗性的實現。

function matchesSelector(element, selec)
  • 1
  • 1
如果呼叫元素與該選擇符匹配,返回true;否則,返回false。
function matchesSelector(element, selector){
    if (element.matchesSelector){
        return element.matchesSelector(selector);
    } else if (element.msMatchesSelector){
        return element.msMatchesSelector(selector);
    } else if (element.mozMatchesSelector){
        return element.mozMatchesSelector(selector);
    } else if (element.webkitMatchesSelector){
        return element.webkitMatchesSelector(selector);
    } else if(ele.matches){
        return ele.matches(selector);
    } else{
        throw new Error("Not supported.");
    }
}
matchesSelector(document.body, "body");     // true
matchesSelector(document.body, "body div"); // false
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

matches.png

二、元素遍歷

對於元素間的空格,各瀏覽器對於childNodes和firstChild等屬性處理行為不一致,為了彌補差異,Element Traversal新定義了一組屬性。 
示例

<p>李剛</p>   
<ul>
    <li>item1</li>
    <li>item2</li>
    <li>item3</li>
    <li>item4</li>
    <li>item5</li>
</ul>
<p id="blog">http://blog.csdn.net/ligang2585116</p>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
屬性 說明 示例
childElementCount 子元素(不包含文字節點和註釋)的個數 5
firstElementChild 指向第一個子元素,firstChild的元素版 <li>​Item 1​</li>
lastElementChild 指向最後一個子元素,lastChild的元素版 <li>​Item 5</li>​
previousElementSibling 指向前一個同輩元素,previousSibling的元素版 <p>李剛</p>
nextElementSibling 指向後一個同輩元素,nextSibling的元素版 <p id="blog">http://blog.csdn.net/ligang2585116</p>
var ul = document.querySelector("ul");
ul.firstChild;  // #text
ul.lastChild;   // <li>​Item 5​</li>​
ul.previousSibling; // #text
ul.nextSibling;     // #text
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

三、HTML5

1. 與類相關的擴充

(1)getElementsByClassName("包含一或多個類名的字串")

document.getElementsByClassName("bj");      // 取得類中包含“bj”的元素
document.getElementsByClassName("bj bd");   // 取得類中同時包含“bj”和“bd”的元素
  • 1
  • 2
  • 1
  • 2

(2)classList屬性 
在操作類名時,需要通過className屬性新增、刪除和替換型別名。因為className中是一個字串,所以即使只修改字串的一部分,也必須每次都設定整個字串的值。

<div class="bd user">ligang</div>
  • 1
  • 1

示例:className方式

var div = document.getElementsByClassName("bd")[0];
var classNames = div.className.split(/\s+/);
// 查詢要刪除的類名"user"
var index = classNames.indexOf("user");
// 刪除類名"user"
classNames.splice(index, 1);
// 重新設定className
div.className = classNames;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

示例:classList方式

var div = document.getElementsByClassName("bd")[0];
div.classList.remove("user");
  • 1
  • 2
  • 1
  • 2

classList屬性是DOMTokenList的例項,其含有length屬性。

屬性 說明
add(value) 將給定的字串新增到列表中。如果已存在,就不新增了
contains(value) 表示列表中是否存在給定的值
remove(value) 從列表中刪除給定的字串
toggle(value) 如果列表中已存在給定的值,刪除它;如果不存在,新增它

有了classList屬性,除非需要刪除全部所有類名,或者完全重寫元素的class屬性,否則也就用不到className屬性了。

2. 焦點管理

document.activeElement屬性始終會引用DOM中當前獲得了焦點的元素。 
示例

var btn = document.getElementById("myBtn");
btn.focus();
console.log(btn.hasFocus());    // true
console.log(document.activeElement === btn); // true
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

預設情況下,文件剛剛載入完成時,document.activeElement中儲存的是document.body元素的引用。文件載入期間,document.activeElement為null。 
查詢文件獲知哪個元素獲得了焦點,以及確定文件是否獲得了焦點,這兩個功能最重要的用途是提高Web應用的無障礙性。無障礙Web應用的一個重要標誌就是恰當的焦點管理,而確切地知道哪個元素獲得了焦點是一個極大的進步。

3. HTMLDocument的變化

(1)readyState屬性

  • loading:正在載入文件;
  • complete:已經載入完文件。 
    使用document.readyState的最恰當方式,就是通過它來實現一個指示文件已經載入完成的指示器。

(2)相容模式 
document.compatMode告知開發人員瀏覽器採用了哪種渲染模式。

  • CSS1Compat:標準模式;
  • BackCompat:混雜模式。

(3)head屬性 
Html5新增了document.head屬性,引用文件的<head>元素。

var head = document.head || document.getElementsByTagName("head")[0];
  • 1
  • 1

4. 字符集屬性

  • document.charset:文件中實際使用的字符集,也可以用來指定新字符集;
  • document.defaultCharset:表示根據瀏覽器及作業系統的設定,當前文件預設的字符集應該是什麼,注意相容性。

5. 自定義資料屬性

HTML5規定可以為元素新增非標準的屬性,但要新增字首data-,目的是為元素提供與渲染無關的資訊,或者提供語義資訊。

<div id="div" data-status="1" data-appId="123" data-customName="ligang">哈哈</div>
  • 1
  • 1

新增了自定義屬性後,可以通過元素的dataset屬性來訪問自定義屬性的值。

var div = document.getElementById("div");
var dataset = div.dataset;
console.log(dataset.appid);     // 123
console.log(dataset.customname);    // "ligang" 注意,都是小寫
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

6. 插入標記

DOM操作文件插入HTML標記非常複雜,因為其不僅要建立一系列DOM節點,而且還要小心地按照正確順序進行連線。詳見:DOM 
示例:建立a標籤並插入到body

var a = document.createElement("a");
a.href = "http://blog.csdn.net/ligang2585116";
a.text = "http://blog.csdn.net/ligang2585116";
document.body.appendChild(a);
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

使用插入標記的技術,直接插入HTML字串不僅簡單而且速度更快。

(1)innerHTML屬性 
讀模式:返回撥用元素的所有節點(包括元素、註釋和文字節點)對應的HTML標記; 
寫模式:根據指定的值建立新的DOM樹,然後用這個DOM樹完全替換呼叫元素原先的所有子節點。 
示例:建立a標籤並插入到body

document.body.innerHTML += '<a href="http://blog.csdn.net/ligang2585116">http://blog.csdn.net/ligang2585116</a>'
  • 1
  • 1

注意:上述使用“+=”,因為寫模式下,innerHTML的值會被解析為DOM子樹,替換呼叫元素原來的所有子節點。 
說明:使用innerHTML插入的字串開頭是一個無作用域的元素(<script>、<style>)時,IE會在解析這個字串前先刪除該元素。

div.innerHTML = "<script>console.logt('hi')</script>";  // 無效
div.innerHTML = "<div>&nbsp;</div><script>console.logt('hi')</script>"; // 有效
div.innerHTML = "<input type=\"hidden\"><script>console.logt('hi')</script>"; // 有效
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

(2)outerHTML屬性 
讀模式:返回撥用它的元素及所有節點(包括元素、註釋和文字節點)對應的HTML標記; 
寫模式:根據指定的值建立新的DOM樹,然後用這個DOM樹完全替換呼叫元素。 
示例:

<div id="blog">
    <!-- blog address -->
    <a href="http://blog.csdn.net/ligang2585116">blog</a>
</div>
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4
var div = document.getElementById("blog");
div.outerHTML;  // 整個innerHTML內容+div本身
div.outerHTML = "<a href=\"http://blog.csdn.net/ligang2585116\">blog</a>";  // 整個div會被a標籤替換掉

// 等價於
var a = document.createElement("a");
a.href = "http://blog.csdn.net/ligang2585116";
a.text = "blog";
div.parentNode.replaceChild(a, div);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

(3)記憶體與效能問題 
使用上述節點方法可能會導致瀏覽器的記憶體佔用問題。在刪除帶有事件處理程式或引用了其他JavaScript物件子樹時,就會導致記憶體佔用問題。在使用innerHTML、outerHTML等方法時,最好先刪除要替換的元素的所有事件處理程式和JavaScript物件屬性。

7. scrollIntoView()方法

如何滾動頁面也是DOM規範沒有解決的一個問題,HTML5最終選擇了scrollIntoView作為標準。 
scrollIntoView()可以在任何元素上呼叫。預設或傳入true,視窗會滾動讓呼叫元素與視口頂部儘可能齊平;傳入false,呼叫元素儘可能會全部出現在視窗中。

document.forms[0].scrollIntoView();
  • 1
  • 1

當頁面發生變化時,一般會用這個方法來吸引使用者的注意力。實際上,為某個元素設定焦點也會導致瀏覽器滾動並顯示出獲得焦點的元素。

四、專有擴充套件

1. children屬性

children屬性與childNodes沒有什麼區別。

2. contains()方法

判斷某個節點是不是另一個節點的後代。

document.body.contains(div); // true
  • 1
  • 1
掩碼 節點關係
1 無關(給定的節點不再當前文件中)
2 居前(給定的節點在DOM樹中位於參考節點之前)
4 居後(給定的節點在DOM樹中位於參考節點之後)
8 包含(給定的節點是參考節點的祖先)
16 被包含(給定的節點是參考節點的後代)

示例:通用的contains函式

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;
            } else {
                node = node.parentNode;
            }
        } while (node !== null);
        return false;
    }
}
console.log(contains(document.documentElement, document.body)); // true
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

3. 插入文字

innerTextouterText並沒有被納入HTML5。 
其對文字進行操作,使用方式類似於innerHTMouterHTML

4. 滾動

HTML5將scrollIntoView()方法納入規範之後,仍還有其他幾個專有方法可以在不同的瀏覽器中使用。 
(1)scrollIntoViewIfNeeded(alignCenter):只在當前元素視口中不可見的情況下,才滾動瀏覽器視窗或容器元素,最終讓它可見。如果當前元素在視口中可見,這個方法什麼也不做。true,儘量將元素在顯示視口中部(垂直方向)。 
scrollIntoViewIfNeeded相容性
(2)scrollByLines(lineCount):將元素的內容滾動指定的行高。 
(3)scrollByPages(pageCount):將元素的內容滾動指定的頁面高度,具體高度由元素的高度決定。 
注意scrollIntoView()scrollIntoViewIfNeeded()的作用物件是元素的容器;scrollByLines()scrollByPages()影響的則是元素自身。

相關文章