初識文件物件模型(DOM)

weixin_33890499發表於2018-06-17

    本篇文章將簡要介紹一下DOM,和目前已經使用過的幾個用來操作DOM的API,由於對DOM的認知還不夠多和深入,因此之後在更全面更深入地瞭解DOM之後,會重新寫一篇關於DOM的部落格。


    DOM的中文名為文件物件模型,英文全稱為Document Object Model,根據阮一峰所寫的JavaScript標準參考教程中寫到:“(DOM)它的作用是將網頁轉為一個 JavaScript 物件,從而可以用指令碼進行各種操作(比如增刪內容)。”
    DOM模型被應用於瀏覽器中,瀏覽器將HTML文件解析成一系列的節點,節點是DOM中最小的單位。由這些節點,節點直接存在著上下級或者兄弟的關係,最後由這些節點組成了一顆節點樹(DOM Tree),所有的節點和最終的樹狀結構,都有規範的對外介面,通過在JavaScript上使用相應的API來操作這些對外介面,就可以間接地操控文件內容。
    在這裡值得注意的是,DOM 只是一個介面規範,可以用各種語言實現,並不只屬於JavaScript。


節點的型別有七種:

Document:整個文件樹的頂層節點
DocumentType:doctype標籤(比如<!DOCTYPE html>)
Element:網頁的各種HTML標籤(比如<body>、<a>等)
Attribute:網頁元素的屬性(比如class="right")
Text:標籤之間或標籤包含的文字
Comment:註釋
DocumentFragment:文件的片段

    瀏覽器提供一個原生的節點物件Node,上面這七種節點都繼承了Node,也就是說所有 DOM 節點都繼承了 Node 介面,因此具有一些共同的屬性和方法。
    這讓我聯想到了物件的__proto__和函式的prototype的關係,這種繼承的關係,很大程度上節省了資源的分配,充分利用了樹形結構的優點。

下面來介紹幾個常用的操控DOM介面的API

(以下的程式碼片段例子均出自JavaScript標準參考教程)

1.Node.textContent

    textContent屬性返回當前節點和它的所有後代節點的文字內容。

// HTML 程式碼為
// <div id="divA">This is <span>some</span> text</div>

document.getElementById('divA').textContent
// This is some text

    該屬性自動忽略當前節點和它的所有後代節點中的非文字內容,然後返回其中的所有文字內容。並且,該屬性是可讀寫的,也就是說可以通過設定該屬性的值,建立一個新的本文內容,來代替該節點的所有子節點,另外,在寫入該屬性的值時,會自動轉譯文字內容中的HTML標籤,會將他們也一併轉譯成文字內容。

2.Node.nextSibling

    Node.nextSibling屬性返回緊跟在當前節點後面的第一個同級節點。如果當前節點後面沒有同級節點,則返回null

// HTML 程式碼如下
// <div id="d1">hello</div><div id="d2">world</div>
var div1 = document.getElementById('d1');
var div2 = document.getElementById('d2');

d1.nextSibling === d2 // true

    根據沒有同級節點就返回null的這個特性,可以通過使用while迴圈以及nextSibling屬性來不斷獲取首個子節點的兄弟節點,知道獲取到的兄弟節點為null為止。

    注意:nextSibling獲取到的後一個同級節點還包括文字節點和評論節點。因此如果當前節點後面有空格,該屬性會返回一個文字節點,內容為空格。
    解決方法:利用Node.nodeType屬性來判斷節點內容,若節點內容為文字內容,則繼續獲取後一個同級節點,直到同級節點為所需節點型別。

3.Node.previousSibling

    previousSibling屬性返回當前節點前面的、距離最近的一個同級節點。如果當前節點前面沒有同級節點,則返回null。

// HTML 程式碼如下
// <div id="d1">hello</div><div id="d2">world</div>
var div1 = document.getElementById('d1');
var div2 = document.getElementById('d2');

d2.previousSibling === d1 // true

    注意:nextSibling獲取到的前一個同級節點還包括文字節點和評論節點。因此如果當前節點前面有空格,該屬性會返回一個文字節點,內容為空格。
    解決方法:利用Node.nodeType屬性來判斷節點內容,若節點內容為文字內容,則繼續獲取前一個同級節點,直到同級節點為所需節點型別。

4.Node.nodeType

    nodeType屬性返回一個整數值,表示節點的型別。
不同節點的nodeType屬性值和對應的常量如下:

文件節點(document):9,對應常量Node.DOCUMENT_NODE
元素節點(element):1,對應常量Node.ELEMENT_NODE
屬性節點(attr):2,對應常量Node.ATTRIBUTE_NODE
文字節點(text):3,對應常量Node.TEXT_NODE
文件片斷節點(DocumentFragment):11,對應常量Node.DOCUMENT_FRAGMENT_NODE
文件型別節點(DocumentType):10,對應常量Node.DOCUMENT_TYPE_NODE
註釋節點(Comment):8,對應常量Node.COMMENT_NODE


5.Node.parentNode

    parentNode屬性返回當前節點的父節點。
    對於一個節點來說,它的父節點只可能是三種型別:元素節點(element)、文件節點(document)和文件片段節點(documentfragment)。
    文件節點(document)和文件片段節點(documentfragment)的父節點都是null。另外,對於那些生成後還沒插入 DOM 樹的節點,父節點也是null
    注意:在這裡值得提醒的是,父節點和父親元素節點的含義的不同,獲取父節點使用的是parentNode屬性,而獲取父元素節點使用parentNode屬性或'parentElement'屬性均可。

6.Node.parentElement

    parentElement屬性返回當前節點的父元素節點。如果當前節點沒有父節點,或者父節點型別不是元素節點,則返回null
    由於父節點只可能是三種型別:元素節點、文件節點(document)和文件片段節點(documentfragment)。parentElement屬性相當於把後兩種父節點都排除了。因此要注意區分屬性parentElement和屬性parentNode的相似之處以及區別。

7.Node.firstChild,Node.lastChild

    firstChild屬性返回當前節點的第一個子節點,如果當前節點沒有子節點,則返回null
    lastChild屬性返回當前節點的最後一個子節點,如果當前節點沒有子節點,則返回null。用法與firstChild屬性相同。
    這裡值得注意的地方與上面的nextSibling屬性相同,就是要注意當前節點之後的文字節點或評論節點不可忽略,因此若要求當前節點的第一個元素子節點,則需要把中間的文字節點和評論節點考慮在內。

8.Node.childNodes

    childNodes屬性返回一個類似陣列的物件(NodeList集合),成員包括當前節點的所有子節點。在返回的物件中,含有length值,代表著當前節點的子節點數,通過這個值可以遍歷所有的子節點。

var children = document.childNodes;
for (var i = 0; i < children.length; i++) {
  console.log(children[i].nodeType);
}
// 10
// 1

    值得注意的是除了元素節點,childNodes屬性的返回值還包括文字節點和註釋節點。如果當前節點不包括任何子節點,則返回一個空的NodeList集合。由於NodeList物件是一個動態集合,一旦子節點發生變化,立刻會反映在返回結果之中。

9.Node.isConnected

    isConnected屬性返回一個布林值,表示當前節點是否在文件之中。

var test = document.createElement('p');
test.isConnected // false

document.body.appendChild(test);
test.isConnected // true

    上面程式碼中,test節點是指令碼生成的節點,沒有插入文件之前,isConnected屬性返回false,插入之後返回true



本教程版權歸宣澤彬所有,轉載須說明來源

相關文章