什麼是DOM
DOM(文檔對象模型)是針對HTML和XML的文檔的一個API ,DOM描繪了一個層次化的節點樹,允許開發人員添加,修改和刪除頁面中的一部分。
節點類型
DOM1定義了一個Node接口,該接口由DOM中所有的節點類型實現。節點類型由在Node類型中定義的12個數值常量來表示,任何節點類型必居其一:
- Node.ELEMENT_NODE(1)
- Node.ATTRIBUTE_NODE(2)
- Node.TEXT_NODE(3)
- Node.CDATA_SECTION_NODE(4)
- Node.ENTITY_REFRENCE_NODE(5)
- Node.ENTITY_NODE(6)
- Node.PROCESSION_INSTRUCTION_NODE(7)
- Node.COMMENT_NODE(8)
- Node.DOCUMENT_NODE(9)
- Node.DOCUMENT_TYPE_NODE(10)
- Node.DOCUMENT_FRAGMENT_NODE(11)
- Node.NOTATION_NODE(12)
每個節點都有一個nodeType
屬性,通過比較上面這些常量可以很容易知道節點的類型,但是由於IE瀏覽器並沒有公開Node類型,因此最好還是將nodeType與數字值進行比較:
if (someNode.nodeType === 1) {
console.log('this is a element');
}
節點屬性
JavaScript中的每個節點都繼承自Node類型,因此每個節點都有相同的基本屬性和方法。
nodeName和nodeValue屬性
可以使用nodeName
和nodeValue
來了解節點的具體信息。這兩個屬性值完全取決於節點的類型,在使用之前最好先像下面這樣進行檢測一下:
if (someNode.nodeType === 1) {
let value = someNode.nodeName; // nodeName的值是元素的標籤名
}
像上面這樣,首先檢測這個節點的類型,看它是不是一個元素,如果是便獲取它的nodeName
的值,對於元素類型的節點來說,nodeName
的值是這個元素的標籤名,而nodeValue
的值始終是null
。
childNodes屬性
每個節點都有一個childNodes
屬性,這個屬性裏面保存着一個NodeList對象
。NodeList
是一個類數組的對象,裏面保存着一組有序的節點。可以通過位置來訪問這些節點。這個NodeList
雖然也有length
屬性,但是它並不是Array
的實例。NodeList
的獨特之處在於,它實際上是根據當前DOM結構進行查詢的結果。因此DOM結構的變化可以在NodeList中反應出來。下面的例子展示瞭如何獲取NodeList中保存的節點:
let firstChild = someNode,childNodes[0];
let secondChild = someNode.childNodes.item(1);
let count = someNode.childNodes.length;
在訪問NodeList
中保存的節點時,使用[]
或者是item()
方法都可以,由於使用[]
比較像數組的語法,所以更受青睞。
previousSibling和nextSibling屬性
childNodes
列表中的每個節點相互之間都是同胞節點。通過使用列表中的previousSibling
和nextSibling
屬性可以訪問列表中的其他節點。列表中的第一個節點的previousSibling屬性值是null,最後一個節點的nextSibling屬性值爲null。如下所示:
if (someNode.nextSibling === null ) {
console.log('this.is the last node');
} else if (someNode.previousSibling === null) {
console.log('this is the first node');
}
parentNode,firstChild,lastChild屬性
每個節點都有一個parentNode
屬性,這個屬性指向文檔樹中的父節點。包含着childNodes
中的所有節點都有一個相同的父節點,因此它們的parentNode屬性指向同一個節點。父節點與childNodes列表中的第一個節點和最後一個節點也有存在着特殊關係。父節點的firstChild
和lastChild
屬性分別指向列表中的第一個子節點和最後一個字節點。其中someNode.fristNode的值等於someNode.childNodes[0]。而someNode.lastNode的值等於someNode.childNodes[someNode.childNodes.length - 1]的值。在只有一個子節點的情況下,firstChild和lastChild屬性指向同一個值,在沒有子節點的情況下,firstChild和lastChild屬性值都爲null。下圖向我們表明了各節點之間的關係:
ownerDocument屬性
所有節點擁有的最後一個屬性是ownerDocument
屬性,該屬性指向表示整個文檔的文檔節點。
hasChildNodes()方法
hasChildNodes()
方法在節點擁有子節點的情況下會返回true
,這比查詢childNodes的length屬性更方便快捷。
操作節點
因爲關係指針都是隻讀的,所以DOM提供了一些操作節點的方法。
appendChild()
appendChild()
用於向childNodes
列表的末尾添加一個節點。添加成功後,childNodes
列表中新增的節點,父節點以及以前的最後一個節點的關係指針都會進行更新,更新完成後,appendChild()返回新增的節點。
let returnedNode = someNode.appendChild(newNode);
console.log(returnedNode === newNode);// true
console.log(someNode.lastChild === newNode); // true
如果appendChild()操作的節點本身是文檔樹的一部分,那麼這個節點就會從當前位置移動到childNodes列表的最後一位。
insertBefore()
如果想把節點插到特定的位置,此時就需要使用insertBefore()
方法,這個方法接受兩個參數:要插入的節點和作爲參照的節點。insertBefore()會將節點插入到參照節點的前面。同時返回新插入的節點。
// 當參照節點是null的時候,插入成爲最後一個節點。
let returnedNode = someNode.insertBefore(newNode, null);
console.log(someNode.lastChild === returnedNode); // true
// 插入成爲第一個節點
let returnedNode = someNode.insertBefor(newNode, someNode.firstChild);
console.log(someNode.firstChild === returnedNode); // true
replaceChild()和removeChild()
- replaceChild()
replaceChild()
方法用來替換節點,它接受兩個參數:要插入的節點和要替換的節點。並返回要替換的節點,而這個要替換的節點會被從DOM樹上刪除。
// 替換第一個節點
let returnedNode = someNode.replaceChild(newNode, someNode.firstChild);
// 替換最後一個節點
let returnedNode = someNode.replaceChild(newNode, someNode.lastChild);
- removeChild()
如果你只想移除某個節點,而並不像替換它,則可以使用removeChild()
方法。這個方法接受一個值,就是要移除的節點,這個要移除的節點會被作爲該方法的返回值進行返回。
// 移除第一個節點
let returnedNode = someNode.removeChild(someNode.firstChild);
// 移除最後一個節點
let returnedNde = someNode,removeChild(someNode.lastChild)
cloneNode()
這個方法是所有的節點都有的,用於創建調用這個方法的節點的一個副本。cloneNode()
方法接受一個布爾值參數,在參數是true
的時候,表示執行深複製,也就是複製節點本身和整個子節點樹。值爲false
,表示執行淺複製,即只複製這個節點本身。複製後返回的節點副本屬於文檔所有,但是並沒有給它指定父元素,因此這個副本就變成了一個“孤兒”。除非將它通過appendChild()
, insertBefore()
,replaceChild()
將它插入到文檔樹中。
假如有以下的HTML結構:
<ul>
<li>item1</li>
<li>item2</li>
<ii>item3<li>
</ul>
假設我們以及把ul元素的引用儲存在了myList
變量中,那麼通過下面代碼就可以看到cloneChild()
兩種模式的區別。
let deepList = myList.cloneChild(true);
console.log(deepList.childNodes.lengh); //3 (IE < 9) 或 7(其他瀏覽器)
let shallowList = myList.cloneChild(false);
console.log(shallowList.childNodes.length); // 0
查找元素
說到常見的DOM應用,恐怕就要數取得特定的幾個或某個元素的引用,從而進行操作了。取得元素的方法可以使用定義在document對象中的一些方法。
getElementById()
getElementById()
接受一個參數,這個參數是要取得的元素的id值**。這裏的id值必須與元素的id屬性值一模一樣**。以下面的元素爲例:
<div id="myDiv">item1</div>
// 可以使用下面的方法獲取到這個div元素
let element = document.getElementById('myDiv');
如果頁面中有多個id值一樣的元素,getElementById()只會返回第一次出現的元素。
getElementsByTagName()
這個方法接受一個參數,即要獲取的元素的標籤名,而返回的是零個或多個元素的NodeList。
// 獲取頁面中的所有的img元素,並將返回的集合保存咋images變量中
let images = document.getElementsByTagName('img');
// 此時的images變量和NodeList很類似,可以使用[]或item()來訪問其中的項
console.log(images.length); //img元素的數量
console.log(images[0].src); // 第一個img元素的src屬性值
getElementsByName()
這個方法會返回帶有給定name
屬性的所有元素。最常使用該方法來獲取單選按鈕,不過要求所有的單元按鈕具備相同的name屬性值
<div>
<ul>
<li> <input type="radio" name="color" value="red" id="colorRed"/></li>
<li> <input type="radio" name="color" value="green" id="colorGreen"/></li>
<li> <input type="radio" name="color" value="blue" id="colorBlue"/></li>
<ul>
</div>
// 獲取name值爲color的單選按鈕元素
var radio = document.getElementsByName("color");
querySelector()
querySelector()
接受一個css選擇符,返回與該模式匹配的第一個元素,如果沒有,就返回null
。
// 獲取body 元素
var body = document.querySelector("body");
// 獲取id爲#myDiv的元素
var div = dosument.querySelector("#myDiv")
// 獲取類爲selector的元素
var element = document.querySelector(".selector")
// 獲取類爲button的第一個ing元素
var img = document.querySelector("img.button")
querySelectorAll()
querySelectorAll()
方法接受的參數與querySelector()一樣,但返回的是所有匹配的元素,而不是第一個元素。
// 獲取類爲selector的元素
var elements = document.querySelectorAll(".selector")
// 獲取p元素中的所有strong元素
var strongs = document.querySelectorAll("p strong");