DOM模型(一)—— DOM模型概述

一、基本概念


1.1牵寺、DOM

DOM是JS操作網(wǎng)頁(yè)的接口,全稱為“文檔對(duì)象模型”(Document Object Model)恩脂。它的作用是將網(wǎng)頁(yè)轉(zhuǎn)為一個(gè)JS對(duì)象帽氓,從而可以用腳本進(jìn)行各種操作(比如增刪內(nèi)容)。

文檔對(duì)象模型(DOM)是網(wǎng)頁(yè)的編程接口俩块。它給文檔(結(jié)構(gòu)樹)提供了一個(gè)結(jié)構(gòu)化的表述并且定義了一種方式——程序可以對(duì)結(jié)構(gòu)樹進(jìn)行訪問黎休,以改變文檔的結(jié)構(gòu),樣式和內(nèi)容玉凯。

DOM提供了一種表述形式將文檔作為一個(gè)結(jié)構(gòu)化的節(jié)點(diǎn)組以及包含屬性和方法的對(duì)象势腮。從本質(zhì)上說,它將web頁(yè)面和腳本或編程語(yǔ)言連接起來了漫仆。

要改變頁(yè)面的某個(gè)東西嫉鲸,JS就需要獲得對(duì)網(wǎng)頁(yè)中所有元素進(jìn)行訪問的入口。這個(gè)入口歹啼,連同對(duì)HTML元素進(jìn)行添加、移動(dòng)翔曲、改變或移除的方法和屬性姜钳,都是通過DOM來獲得的。

瀏覽器會(huì)根據(jù)DOM模型浴滴,將結(jié)構(gòu)化文檔(比如HTML和XML)解析成一系列的節(jié)點(diǎn),再由這些節(jié)點(diǎn)組成一個(gè)樹狀結(jié)構(gòu)(DOM Tree)岁钓。所有的節(jié)點(diǎn)和最終的樹狀結(jié)構(gòu)升略,都有規(guī)范的對(duì)外接口。所以屡限,DOM可以理解成網(wǎng)頁(yè)的編程接口品嚣。DOM有自己的國(guó)際標(biāo)準(zhǔn),目前的通用版本是DOM 3钧大,下一代的DOM 4正在擬定中翰撑。

嚴(yán)格地說,DOM不屬于JS啊央,但是操作DOM是JS最常見的任務(wù)眶诈,而JS也是最常用于DOM操作的語(yǔ)言。本章介紹的就是JS對(duì)DOM標(biāo)準(zhǔn)的實(shí)現(xiàn)和用法瓜饥。

1.2逝撬、節(jié)點(diǎn)

DOM的最小組成單位叫做節(jié)點(diǎn)(node)。文檔的樹形結(jié)構(gòu)(DOM樹)乓土,就是由各種不同類型的節(jié)點(diǎn)組成宪潮。每個(gè)節(jié)點(diǎn)可以看作是文檔樹的一片葉子。

節(jié)點(diǎn)的類型有七種趣苏。

  • Document:整個(gè)文檔樹的頂層節(jié)點(diǎn)狡相,也是訪問的入口。
  • DocumentType:doctype標(biāo)簽(比如<!DOCTYPE html>)拦键。
  • Element:網(wǎng)頁(yè)的各種HTML標(biāo)簽(比如<body>谣光、<a>等)。
  • Attribute:網(wǎng)頁(yè)元素的屬性(比如class="right")芬为。
  • Text:標(biāo)簽之間或標(biāo)簽包含的文本萄金。
  • Comment:注釋。
  • DocumentFragment:文檔的片段媚朦。

這七種節(jié)點(diǎn)都屬于瀏覽器原生提供的節(jié)點(diǎn)對(duì)象(下面要講的Node對(duì)象)的派生對(duì)象氧敢,具有一些共同的屬性和方法。

1.3询张、節(jié)點(diǎn)樹

一個(gè)文檔的所有節(jié)點(diǎn)孙乖,按照所在的層級(jí),可以抽象成一種樹狀結(jié)構(gòu)。這種樹狀結(jié)構(gòu)就是DOM唯袄。

DOM

最頂層的節(jié)點(diǎn)就是document節(jié)點(diǎn)弯屈,它代表了整個(gè)文檔。文檔里面最高的HTML標(biāo)簽恋拷,一般是<html>资厉,它構(gòu)成樹結(jié)構(gòu)的根節(jié)點(diǎn)(root node),其他HTML標(biāo)簽節(jié)點(diǎn)都是它的下級(jí)蔬顾。

除了根節(jié)點(diǎn)以外宴偿,其他節(jié)點(diǎn)對(duì)于周圍的節(jié)點(diǎn)都存在三種關(guān)系。

  • 父節(jié)點(diǎn)關(guān)系(parentNode):直接的那個(gè)上級(jí)節(jié)點(diǎn)诀豁。
  • 子節(jié)點(diǎn)關(guān)系(childNode):直接的下級(jí)節(jié)點(diǎn)窄刘。
  • 同級(jí)節(jié)點(diǎn)關(guān)系(sibling):擁有同一父節(jié)點(diǎn)的節(jié)點(diǎn)。

DOM提供操作接口舷胜,用來獲取三種關(guān)系的節(jié)點(diǎn)娩践。其中,子節(jié)點(diǎn)接口包括firstChild(第一個(gè)子節(jié)點(diǎn))和lastChild(最后一個(gè)子節(jié)點(diǎn))等屬性逞带,同級(jí)節(jié)點(diǎn)接口包括nextSibling(緊鄰在后的那個(gè)同級(jí)節(jié)點(diǎn))和previousSibling(緊鄰在前的那個(gè)同級(jí)節(jié)點(diǎn))屬性欺矫。

二纱新、與節(jié)點(diǎn)本身特征相關(guān)的屬性


所有節(jié)點(diǎn)對(duì)象都是瀏覽器內(nèi)置的Node對(duì)象的實(shí)例展氓,繼承了Node屬性和方法。這是所有節(jié)點(diǎn)的共同特征脸爱。

以下屬性與節(jié)點(diǎn)對(duì)象本身的特征相關(guān)遇汞。這些屬性是實(shí)例對(duì)象(也就是節(jié)點(diǎn)對(duì)象)繼承自Node.prototype對(duì)象的。

2.1簿废、Node.nodeName空入、Node.nodeType

nodeName屬性返回節(jié)點(diǎn)的名稱,nodeType屬性返回節(jié)點(diǎn)類型的常數(shù)值族檬。

七種類型節(jié)點(diǎn)

document節(jié)點(diǎn)為例歪赢,它的nodeName屬性等于#documentnodeType屬性等于9单料。

驗(yàn)證

通常來說埋凯,使用nodeType屬性確定一個(gè)節(jié)點(diǎn)的類型,比較方便扫尖。

document.querySelector('p').nodeType === 1
// true

document.querySelector('p').nodeType === Node.ELEMENT_NODE
// true

上面兩種寫法等價(jià)白对。

驗(yàn)證

2.2、Node.nodeValue

nodeValue屬性返回一個(gè)字符串换怖,表示當(dāng)前節(jié)點(diǎn)本身的文本值甩恼,該屬性可讀寫。

由于只有Text節(jié)點(diǎn)、Comment節(jié)點(diǎn)条摸、XML文檔的CDATA節(jié)點(diǎn)有文本值悦污,因此只有這三類節(jié)點(diǎn)的nodeValue可以返回結(jié)果,其他類型的節(jié)點(diǎn)一律返回null钉蒲。同樣的塞关,也只有這三類節(jié)點(diǎn)可以設(shè)置nodeValue屬性的值。對(duì)于那些返回null的節(jié)點(diǎn)子巾,設(shè)置nodeValue屬性是無效的帆赢。

2.3、Node.textContent

textContent屬性返回當(dāng)前節(jié)點(diǎn)和它的所有后代節(jié)點(diǎn)的文本內(nèi)容线梗。

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

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

textContent屬性自動(dòng)忽略當(dāng)前節(jié)點(diǎn)內(nèi)部的HTML標(biāo)簽椰于,返回所有文本內(nèi)容。

該屬性是可讀寫的仪搔,設(shè)置該屬性的值瘾婿,會(huì)用一個(gè)新的文本節(jié)點(diǎn),替換所有原來的子節(jié)點(diǎn)烤咧。它有一個(gè)好處偏陪,就是自動(dòng)對(duì)HTML標(biāo)簽轉(zhuǎn)義。這很適合用于用戶提供的內(nèi)容煮嫌。

document.getElementById('foo').textContent = '<p>GoodBye!</p>';

上面代碼在插入文本時(shí)笛谦,會(huì)將<p>標(biāo)簽解釋為文本,而不會(huì)當(dāng)作標(biāo)簽處理昌阿。

對(duì)于Text節(jié)點(diǎn)和Comment節(jié)點(diǎn)饥脑,該屬性的值與nodeValue屬性相同。對(duì)于其他類型的節(jié)點(diǎn)懦冰,該屬性會(huì)將每一個(gè)子節(jié)點(diǎn)的內(nèi)容連接在一起返回灶轰,但是不包括Comment節(jié)點(diǎn)。如果一個(gè)節(jié)點(diǎn)沒有子節(jié)點(diǎn)刷钢,則返回空字符串笋颤。

document節(jié)點(diǎn)和doctype節(jié)點(diǎn)的textContent屬性為null。如果要讀取整個(gè)文檔的內(nèi)容内地,可以使用document.documentElement.textContent伴澄。

2.4、Node.baseURI

Node.baseURI屬性返回一個(gè)字符串瓤鼻,表示當(dāng)前網(wǎng)頁(yè)的絕對(duì)路徑秉版。如果無法取到這個(gè)值,則返回null茬祷。瀏覽器根據(jù)這個(gè)屬性清焕,計(jì)算網(wǎng)頁(yè)上的相對(duì)路徑的URL。該屬性為只讀。

不同節(jié)點(diǎn)都可以調(diào)用這個(gè)屬性(比如document.baseURIelement.baseURI)秸妥,通常它們的值是相同的滚停。

該屬性的值一般由當(dāng)前網(wǎng)址的URL(即window.location屬性)決定,但是可以使用HTML的<base>標(biāo)簽粥惧,改變?cè)搶傩缘闹怠?/p>

三键畴、返回當(dāng)前節(jié)點(diǎn)相關(guān)節(jié)點(diǎn)的屬性


以下屬性返回當(dāng)前節(jié)點(diǎn)的相關(guān)節(jié)點(diǎn)。

3.1突雪、Node.ownerDocument

Node.ownerDocument屬性返回當(dāng)前節(jié)點(diǎn)所在的頂層文檔對(duì)象起惕,即document對(duì)象。

var d = p.ownerDocument;
d === document  //true

document對(duì)象本身的ownerDocument屬性咏删,返回null惹想。

驗(yàn)證

3.2、Node.nextSibling

nextSibling屬性返回緊跟在當(dāng)前節(jié)點(diǎn)后面的第一個(gè)同級(jí)節(jié)點(diǎn)督函。如果當(dāng)前節(jié)點(diǎn)后面沒有同級(jí)節(jié)點(diǎn)嘀粱,則返回null

注意辰狡,該屬性還包括文本節(jié)點(diǎn)和注釋節(jié)點(diǎn)锋叨。因此如果當(dāng)前節(jié)點(diǎn)后面有空格,該屬性會(huì)返回一個(gè)文本節(jié)點(diǎn)宛篇,內(nèi)容為空格娃磺。

3.3、Node.previousSibling

previousSibling屬性返回當(dāng)前節(jié)點(diǎn)前面的些己、距離最近的一個(gè)同級(jí)節(jié)點(diǎn)豌鸡。如果當(dāng)前節(jié)點(diǎn)前面沒有同級(jí)節(jié)點(diǎn)嘿般,則返回null段标。

// html代碼如下
// <a><b1 id="b1"/><b2 id="b2"/></a>

document.getElementById("b1").previousSibling // null
document.getElementById("b2").previousSibling.id // "b1"

對(duì)于當(dāng)前節(jié)點(diǎn)前面有空格,則previousSibling屬性會(huì)返回一個(gè)內(nèi)容為空格的文本節(jié)點(diǎn)炉奴。

3.4逼庞、Node.parentNode

parentNode屬性返回當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn)。對(duì)于一個(gè)節(jié)點(diǎn)來說瞻赶,它的父節(jié)點(diǎn)只可能是三種類型:element節(jié)點(diǎn)赛糟、document節(jié)點(diǎn)和documentFragment節(jié)點(diǎn)。

下面是如何從父節(jié)點(diǎn)移除指定節(jié)點(diǎn)砸逊。

if(node.parentNode){
    node.parentNode.removeChild(node);
}

對(duì)于document節(jié)點(diǎn)和documentFragment節(jié)點(diǎn)璧南,它們的父節(jié)點(diǎn)都是null。另外师逸,對(duì)于那些生成后還沒插入DOM樹的節(jié)點(diǎn)司倚,父節(jié)點(diǎn)也是null

3.5、Node.parentElement

parentElement屬性返回當(dāng)前節(jié)點(diǎn)的父Element節(jié)點(diǎn)动知。如果當(dāng)前節(jié)點(diǎn)沒有父節(jié)點(diǎn)皿伺,或者父節(jié)點(diǎn)類型不是Element節(jié)點(diǎn),則返回null盒粮。

if (node.parentElement) {
  node.parentElement.style.color = "red";
}

上面代碼設(shè)置指定節(jié)點(diǎn)的父Element節(jié)點(diǎn)的CSS屬性鸵鸥。

在IE瀏覽器中,只有Element節(jié)點(diǎn)才有該屬性丹皱,其他瀏覽器則是所有類型的節(jié)點(diǎn)都有該屬性妒穴。

3.6、Node.childNodes

childNodes屬性返回一個(gè)NodeList集合摊崭,成員包括當(dāng)前節(jié)點(diǎn)的所有子節(jié)點(diǎn)宰翅。注意,除了HTML元素節(jié)點(diǎn)爽室,該屬性返回的還包括Text節(jié)點(diǎn)和Comment節(jié)點(diǎn)汁讼。如果當(dāng)前節(jié)點(diǎn)不包括任何子節(jié)點(diǎn),則返回一個(gè)空的NodeList集合阔墩。由于NodeList對(duì)象是一個(gè)動(dòng)態(tài)集合嘿架,一旦子節(jié)點(diǎn)發(fā)生變化,立刻會(huì)反映在返回結(jié)果之中啸箫。

var ulElementChildNodes = document.querySelector('ul').childNodes;

3.7耸彪、Node.firstChild、Node.lastChild

firstChild屬性返回當(dāng)前節(jié)點(diǎn)的第一個(gè)子節(jié)點(diǎn)忘苛,如果當(dāng)前節(jié)點(diǎn)沒有子節(jié)點(diǎn)蝉娜,則返回null

//HTML
<p id="para-01"><span>First span</span></p>

//JS
document.getElementById('para-01').firstChild.nodeName
//"span"
結(jié)果

注意扎唾,firstChild返回的除了HTML元素子節(jié)點(diǎn)召川,還可能是文本節(jié)點(diǎn)或注釋節(jié)點(diǎn)。

//HTML
<p id="para-01">
    <span>First span</span>
</p>

//JS
document.getElementById('para-01').firstChild.nodeName
//"#text"

上面的代碼中胸遇,p元素與span元素之間有空白字符荧呐,這導(dǎo)致firstChild返回的是文本節(jié)點(diǎn)。

結(jié)果

lastChild屬性返回當(dāng)前節(jié)點(diǎn)的最后一個(gè)子節(jié)點(diǎn)纸镊,如果當(dāng)前節(jié)點(diǎn)沒有子節(jié)點(diǎn)倍阐,則返回null

四逗威、節(jié)點(diǎn)對(duì)象的方法


4.1峰搪、Node.appendChild()

appendChild方法接受一個(gè)節(jié)點(diǎn)對(duì)象作為參數(shù),將其作為最后一個(gè)節(jié)點(diǎn)凯旭,插入當(dāng)前節(jié)點(diǎn)概耻。

var p = document.createElement('p');
document.body.appendChild(p);

如果參數(shù)節(jié)點(diǎn)時(shí)DOM中已經(jīng)存在的節(jié)點(diǎn)楣颠,appendChild方法會(huì)將其從原來的位置,移動(dòng)到新位置咐蚯。

4.2童漩、Node.hasChildNodes()

hasChildNodes方法返回一個(gè)布爾值,表示當(dāng)前節(jié)點(diǎn)是否有子節(jié)點(diǎn)春锋。

var foo = document.getElementById("foo");

if (foo.hasChildNodes()) {
    foo.removeChild(foo.childNodes[0]);
}

上面代碼表示矫膨,如果foo節(jié)點(diǎn)有子節(jié)點(diǎn),就移除第一個(gè)子節(jié)點(diǎn)期奔。

hasChildNodes方法結(jié)合firstChild屬性和nextSibling屬性侧馅,可以遍歷當(dāng)前節(jié)點(diǎn)的所有后代節(jié)點(diǎn)。

4.3呐萌、Node.cloneNode()

cloneNode方法用于克隆一個(gè)節(jié)點(diǎn)馁痴。它接受一個(gè)布爾值作為參數(shù),表示是否同時(shí)克隆子節(jié)點(diǎn)肺孤,默認(rèn)是false罗晕,即不克隆子節(jié)點(diǎn)。

var cloneUL = document.querySelector('ul').cloneNode(true);

需要注意的是赠堵,克隆一個(gè)節(jié)點(diǎn)小渊,會(huì)拷貝該節(jié)點(diǎn)的所有屬性,但是會(huì)喪失addEventListener方法和on-屬性(即node.onclick = fn)茫叭,添加在這個(gè)節(jié)點(diǎn)上的事件回調(diào)函數(shù)酬屉。

克隆一個(gè)節(jié)點(diǎn)之后,DOM樹有可能出現(xiàn)兩個(gè)有相同ID屬性的HTML元素揍愁,這時(shí)應(yīng)該修改其中一個(gè)HTML元素的ID屬性呐萨。

4.4、Node.insertBefore()

insertBefore方法用于將某個(gè)節(jié)點(diǎn)插入當(dāng)前節(jié)點(diǎn)的指定位置莽囤。它接受兩個(gè)參數(shù)谬擦,第一個(gè)參數(shù)是所要插入的節(jié)點(diǎn),第二個(gè)參數(shù)是當(dāng)前節(jié)點(diǎn)的一個(gè)子節(jié)點(diǎn)烁登,新的節(jié)點(diǎn)將插在這個(gè)節(jié)點(diǎn)的前面怯屉。該方法返回被插入的新節(jié)點(diǎn)。

var text1 = document.createTextNode('1');
var li = document.createElement('li');
li.appendChild(text1);

var ul = document.querySelector('ul');
ul.insertBefore(li, ul.firstChild);

上面代碼使用當(dāng)前節(jié)點(diǎn)的firstChild屬性饵沧,在<ul>節(jié)點(diǎn)的最前面插入一個(gè)新建的<li>節(jié)點(diǎn),新節(jié)點(diǎn)變成第一個(gè)子節(jié)點(diǎn)赌躺。

parentElement.insertBefore(newElement, parentElement.firstChild);

上面代碼中狼牺,如果當(dāng)前節(jié)點(diǎn)沒有任何子節(jié)點(diǎn),parentElement.firstChild會(huì)返回null礼患,則新節(jié)點(diǎn)會(huì)成為當(dāng)前節(jié)點(diǎn)的唯一子節(jié)點(diǎn)是钥。

如果insertBefore方法的第二個(gè)參數(shù)為null掠归,則新節(jié)點(diǎn)將插在當(dāng)前節(jié)點(diǎn)的最后位置,即變成最后一個(gè)子節(jié)點(diǎn)悄泥。

注意虏冻,如果所要插入的節(jié)點(diǎn)是當(dāng)前DOM現(xiàn)有的節(jié)點(diǎn),則該節(jié)點(diǎn)將從原有的位置移除弹囚,插入新的位置厨相。

由于不存在insertAfter方法,如果要插在當(dāng)前節(jié)點(diǎn)的某個(gè)子節(jié)點(diǎn)后面鸥鹉,可以用insertBefore方法結(jié)合nextSibling屬性模擬蛮穿。

parentDiv.insertBefore(s1, s2.nextSibling);

上面代碼可以將s1節(jié)點(diǎn),插在s2節(jié)點(diǎn)后面毁渗。如果s2是當(dāng)前節(jié)點(diǎn)的最后一個(gè)子節(jié)點(diǎn)践磅,則s2.nextSibling返回null,這時(shí)s1節(jié)點(diǎn)會(huì)插在當(dāng)前節(jié)點(diǎn)的最后灸异,變成當(dāng)前節(jié)點(diǎn)的最后一個(gè)子節(jié)點(diǎn)府适,等于緊跟在s2的后面。

4.5肺樟、Node.removeChild()

removeChild方法接受一個(gè)子節(jié)點(diǎn)作為參數(shù)细溅,用于從當(dāng)前節(jié)點(diǎn)移除該子節(jié)點(diǎn),它返回被移除的子節(jié)點(diǎn)儡嘶。

var divA = document.getElementById('A');
divA.parentNode.removeChild(divA);

上面代碼是如何移除一個(gè)指定節(jié)點(diǎn)喇聊。

注意,這個(gè)方法是在父節(jié)點(diǎn)上調(diào)用蹦狂,不是在被移除的節(jié)點(diǎn)上調(diào)用的誓篱。

下面是如何移除當(dāng)前節(jié)點(diǎn)的所有子節(jié)點(diǎn)。

var element = document.getElementById('top');
while (element.firstChild) {
  element.removeChild(element.firstChild);
}

被移除的節(jié)點(diǎn)依然存在于內(nèi)存之中凯楔,但不再是DOM的一部分窜骄。所以,一個(gè)節(jié)點(diǎn)移除以后摆屯,依然可以使用它邻遏,比如插入到另一個(gè)節(jié)點(diǎn)下面。

4.6虐骑、Node.replaceChild()

replaceChild方法用于將一個(gè)新節(jié)點(diǎn)准验,替換當(dāng)前節(jié)點(diǎn)的某一個(gè)子節(jié)點(diǎn)。它接受兩個(gè)參數(shù)廷没,第一個(gè)參數(shù)是用來替換的新節(jié)點(diǎn)糊饱,第二個(gè)參數(shù)是將要被替換走的子節(jié)點(diǎn)。它返回被替換走的那個(gè)節(jié)點(diǎn)颠黎。

replacedNode = parentNode.replaceChild(newChild, oldChild);

下面是一個(gè)例子另锋。

var divA = document.getElementById('A');
var newSpan = document.createElement('span');
newSpan.textContent = 'Hello World!';
divA.parentNode.replaceChild(newSpan, divA);

上面代碼是如何替換指定節(jié)點(diǎn)滞项。

4.7、Node.contains()

contains方法接受一個(gè)節(jié)點(diǎn)作為參數(shù)夭坪,返回一個(gè)布爾值文判,表示參數(shù)節(jié)點(diǎn)是否為當(dāng)前節(jié)點(diǎn)的后代節(jié)點(diǎn)。

document.body.contains(node)

上面代碼檢查某個(gè)節(jié)點(diǎn)室梅,是否包含在當(dāng)前文檔之中戏仓。

注意,如果將當(dāng)前節(jié)點(diǎn)傳入contains方法竞惋,會(huì)返回true柜去。雖然從意義上說,一個(gè)節(jié)點(diǎn)不應(yīng)該包含自身拆宛。

nodeA.contains(nodeA) // true

4.8嗓奢、Node.compareDocumentPosition()

compareDocumentPosition方法的用法,與contains方法完全一致浑厚,返回一個(gè)7個(gè)比特位的二進(jìn)制值股耽,表示參數(shù)節(jié)點(diǎn)與當(dāng)前節(jié)點(diǎn)的關(guān)系。

4.9钳幅、Node.isEqualNode()

isEqualNode方法返回一個(gè)布爾值物蝙,用于檢查兩個(gè)節(jié)點(diǎn)是否相等。所謂相等的節(jié)點(diǎn)敢艰,指的是兩個(gè)節(jié)點(diǎn)的類型相同诬乞、屬性相同、子節(jié)點(diǎn)相同钠导。

var targetEl = document.getElementById("targetEl");
var firstDiv = document.getElementsByTagName("div")[0];

targetEl.isEqualNode(firstDiv)

4.10震嫉、Node.normalize()

normalize方法用于清理當(dāng)前節(jié)點(diǎn)內(nèi)部的所有Text節(jié)點(diǎn)。它會(huì)去除空的文本節(jié)點(diǎn)牡属,并且將毗鄰的文本節(jié)點(diǎn)合并成一個(gè)票堵。

var wrapper = document.createElement("div");

wrapper.appendChild(document.createTextNode("Part 1 "));
wrapper.appendChild(document.createTextNode("Part 2 "));

wrapper.childNodes.length // 2

wrapper.normalize();

wrapper.childNodes.length // 1

上面代碼使用normalize方法之前,wrapper節(jié)點(diǎn)有兩個(gè)Text子節(jié)點(diǎn)逮栅。使用nomalize方法之后悴势,兩個(gè)Text子節(jié)點(diǎn)被合成一個(gè)。

該方法是Text.splitText的逆方法措伐。

五特纤、NodeList對(duì)象,HTMLCollection對(duì)象


節(jié)點(diǎn)都是單個(gè)對(duì)象废士,有時(shí)會(huì)需要一種數(shù)據(jù)結(jié)構(gòu)叫潦,能夠容納多個(gè)節(jié)點(diǎn)。DOM提供兩種集合對(duì)象官硝,用于實(shí)現(xiàn)這種節(jié)點(diǎn)的集合:NodeListHTMLCollection矗蕊。

這兩個(gè)對(duì)象都是構(gòu)造函數(shù)。

typeof NodeList  //"function"
typeof HTMLCollection  //"function"

但是氢架,一般不把它們當(dāng)作函數(shù)使用傻咖,甚至都沒有直接使用它們的場(chǎng)合。主要是許多DOM屬性和方法岖研,返回的結(jié)果是NodeList實(shí)例或HTMLCollection實(shí)例卿操,所以一般只使用它們的實(shí)例

5.1孙援、NodeList實(shí)例對(duì)象

NodeList實(shí)例對(duì)象是一個(gè)類似數(shù)組的對(duì)象害淤,它的成員是節(jié)點(diǎn)對(duì)象。

Node.childNodes拓售、document.querySelectorAll()返回的都是NodeList實(shí)例對(duì)象窥摄。

document.childNodes instanceof NodeList  // true

NodeList實(shí)例對(duì)象可能是動(dòng)態(tài)集合,也可能是靜態(tài)集合础淤。所謂動(dòng)態(tài)集合就是一個(gè)活的集合崭放,DOM樹刪除或新增一個(gè)相關(guān)節(jié)點(diǎn),都會(huì)立刻反映在NodeList接口之中鸽凶。Node.childNodes返回的币砂,就是一個(gè)動(dòng)態(tài)集合

var parent = document.getElementById('parent');
parent.childNodes.length // 2
parent.appendChild(document.createElement('div'));
parent.childNodes.length // 3

上面代碼中玻侥,parent.childNodes返回的是一個(gè)NodeList實(shí)例對(duì)象决摧。當(dāng)parent節(jié)點(diǎn)新增一個(gè)子節(jié)點(diǎn)以后,該對(duì)象的成員個(gè)數(shù)就增加了1凑兰。

document.querySelectorAll方法返回的是一個(gè)靜態(tài)集合掌桩。DOM內(nèi)部的變化,并不會(huì)實(shí)時(shí)反映在該方法的返回結(jié)果之中票摇。

NodeList接口實(shí)例對(duì)象提供length屬性和數(shù)字索引拘鞋,因此可以像數(shù)組那樣,使用數(shù)字索引取出每個(gè)節(jié)點(diǎn)矢门,但是它們本身并不是數(shù)組盆色,不能使用數(shù)組特有的方法。

//數(shù)組的繼承鏈
myArray  --> Array.prototype--> Object.prototype --> null

//NodeList的繼承鏈
myNodeList --> NodeList.prototype --> Object.prototype --> null

5.2祟剔、HTMLCollection實(shí)例對(duì)象

HTMLCollection實(shí)例對(duì)象與NodeList實(shí)例對(duì)象類似隔躲,也是節(jié)點(diǎn)的集合,返回一個(gè)類似數(shù)組的對(duì)象物延。
document.links宣旱、document.formsdocument.images等屬性叛薯,返回的都是HTMLCollection實(shí)例對(duì)象浑吟。

HTMLCollectionNodeList的區(qū)別有以下幾點(diǎn)笙纤。
(1)、HTMLCollection實(shí)例對(duì)象的成員只能是Element節(jié)點(diǎn)组力,NodeList實(shí)例對(duì)象的成員可以包含其他節(jié)點(diǎn)省容。
(2)、HTMLCollection實(shí)例對(duì)象都是動(dòng)態(tài)集合燎字,節(jié)點(diǎn)的變化會(huì)實(shí)時(shí)反映在集合中腥椒。NodeList實(shí)例對(duì)象可以是靜態(tài)集合。
(3)候衍、HTMLCollection實(shí)例對(duì)象可以用id屬性或name屬性引用節(jié)點(diǎn)元素笼蛛,NodeList實(shí)例對(duì)象只能使用數(shù)字索引引用。

HTMLCollection實(shí)例的item方法蛉鹿,可以根據(jù)成員的位置參數(shù)(從0開始)滨砍,返回該成員。如果取不到成員或數(shù)字索引不合法榨为,則返回null惨好。

var c = document.images;
var img1 = c.item(1);

//等價(jià)于下面的寫法
var img1 = c[1];

HTMLCollection實(shí)例的namedItem方法根據(jù)成員的ID屬性或name屬性,返回該成員随闺。如果沒有對(duì)應(yīng)的成員日川,則返回null。這個(gè)方法是NodeList實(shí)例不具有的矩乐。

// HTML代碼為
// <form id="myForm"></form>
var elem = document.forms.namedItem('myForm');
// 等價(jià)于下面的寫法
var elem = document.forms['myForm'];

由于item方法和namedItem方法龄句,都可以用方括號(hào)運(yùn)算符代替,所以建議一律使用方括號(hào)運(yùn)算符散罕。

六分歇、ParentNode接口,ChildNode接口


不同的節(jié)點(diǎn)除了繼承Node接口以外欧漱,還會(huì)繼承其他接口职抡。ParentNode接口用于獲取當(dāng)前節(jié)點(diǎn)的Element子節(jié)點(diǎn),ChildNode接口用于處理當(dāng)前節(jié)點(diǎn)的子節(jié)點(diǎn)(包含但不限于Element子節(jié)點(diǎn))误甚。

6.1缚甩、ParentNode接口

ParentNode接口用于獲取Element子節(jié)點(diǎn)。Element節(jié)點(diǎn)窑邦、Document節(jié)點(diǎn)和DocumentFragment節(jié)點(diǎn)擅威,部署了ParentNode接口。凡是這三類節(jié)點(diǎn)冈钦,都具有以下四個(gè)屬性郊丛,用于獲取Element子節(jié)點(diǎn)。

(1)、children
children屬性返回一個(gè)動(dòng)態(tài)的HTMLCollection集合厉熟,由當(dāng)前節(jié)點(diǎn)的所有Element子節(jié)點(diǎn)組成导盅。

(2)、firstElementChild
firstElementChild屬性返回當(dāng)前節(jié)點(diǎn)的第一個(gè)Element子節(jié)點(diǎn)庆猫,如果不存在任何Element子節(jié)點(diǎn)认轨,則返回null绅络。

document.firstElementChild.nodeName
// "HTML"

上面代碼中月培,document節(jié)點(diǎn)的第一個(gè)Element子節(jié)點(diǎn)是<HTML>

(3)恩急、lastElementChild
lastElementChild屬性返回當(dāng)前節(jié)點(diǎn)的最后一個(gè)Element子節(jié)點(diǎn)杉畜,如果不存在任何Element子節(jié)點(diǎn),則返回null衷恭。

document.lastElementChild.nodeName
// "HTML"

上面代碼中此叠,document節(jié)點(diǎn)的最后一個(gè)Element子節(jié)點(diǎn)是<HTML>

(4)随珠、childElementCount
childElementCount屬性返回當(dāng)前節(jié)點(diǎn)的所有Element子節(jié)點(diǎn)的數(shù)目灭袁。

6.2、ChildNode接口

ChildNode接口用于處理子節(jié)點(diǎn)(包含但不限于Element子節(jié)點(diǎn))窗看。Element節(jié)點(diǎn)茸歧、DocumentType節(jié)點(diǎn)和CharacterData接口,部署了ChildNode接口显沈。凡是這三類節(jié)點(diǎn)(接口)软瞎,都可以使用下面四種方法。

(1)拉讯、remove()
remove方法用于移除當(dāng)前節(jié)點(diǎn)涤浇。

el.remove()

上面方法在DOM中移除el節(jié)點(diǎn)。注意魔慷,調(diào)用這個(gè)方法的節(jié)點(diǎn)只锭,是被移除的節(jié)點(diǎn)本身,而不是它的父節(jié)點(diǎn)院尔。

(2)蜻展、before()
before方法用于在當(dāng)前節(jié)點(diǎn)的前面,插入一個(gè)同級(jí)節(jié)點(diǎn)召边。如果參數(shù)是節(jié)點(diǎn)對(duì)象铺呵,插入DOM的就是該節(jié)點(diǎn)對(duì)象;如果參數(shù)是文本隧熙,插入DOM的就是參數(shù)對(duì)應(yīng)的文本節(jié)點(diǎn)片挂。

(3)、after()
after方法用于在當(dāng)前節(jié)點(diǎn)的后面,插入一個(gè)同級(jí)節(jié)點(diǎn)音念。如果參數(shù)是節(jié)點(diǎn)對(duì)象沪饺,插入DOM的就是該節(jié)點(diǎn)對(duì)象;如果參數(shù)是文本闷愤,插入DOM的就是參數(shù)對(duì)應(yīng)的文本節(jié)點(diǎn)整葡。

(4)、replaceWith()
replaceWith方法使用參數(shù)指定的節(jié)點(diǎn)讥脐,替換當(dāng)前節(jié)點(diǎn)遭居。如果參數(shù)是節(jié)點(diǎn)對(duì)象。替換當(dāng)前節(jié)點(diǎn)的就是該節(jié)點(diǎn)對(duì)象旬渠;如果參數(shù)是文本俱萍,替換當(dāng)前節(jié)點(diǎn)的就是參數(shù)對(duì)應(yīng)的文本節(jié)點(diǎn)。

(本系列下一節(jié)為 — Document節(jié)點(diǎn))

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末告丢,一起剝皮案震驚了整個(gè)濱河市枪蘑,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌岖免,老刑警劉巖岳颇,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異颅湘,居然都是意外死亡话侧,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門栅炒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來掂摔,“玉大人,你說我怎么就攤上這事赢赊∫依欤” “怎么了?”我有些...
    開封第一講書人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵释移,是天一觀的道長(zhǎng)叭披。 經(jīng)常有香客問我,道長(zhǎng)玩讳,這世上最難降的妖魔是什么涩蜘? 我笑而不...
    開封第一講書人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮熏纯,結(jié)果婚禮上同诫,老公的妹妹穿的比我還像新娘。我一直安慰自己樟澜,他們只是感情好误窖,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開白布叮盘。 她就那樣靜靜地躺著,像睡著了一般霹俺。 火紅的嫁衣襯著肌膚如雪柔吼。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,624評(píng)論 1 305
  • 那天丙唧,我揣著相機(jī)與錄音愈魏,去河邊找鬼。 笑死想际,一個(gè)胖子當(dāng)著我的面吹牛培漏,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播沼琉,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼北苟,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了打瘪?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤傻昙,失蹤者是張志新(化名)和其女友劉穎闺骚,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體妆档,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡僻爽,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了贾惦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片胸梆。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖须板,靈堂內(nèi)的尸體忽然破棺而出碰镜,到底是詐尸還是另有隱情,我是刑警寧澤习瑰,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布绪颖,位于F島的核電站,受9級(jí)特大地震影響甜奄,放射性物質(zhì)發(fā)生泄漏柠横。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一课兄、第九天 我趴在偏房一處隱蔽的房頂上張望牍氛。 院中可真熱鬧,春花似錦烟阐、人聲如沸搬俊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)悠抹。三九已至珠月,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間楔敌,已是汗流浹背啤挎。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留卵凑,地道東北人庆聘。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像勺卢,于是被迫代替她去往敵國(guó)和親伙判。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容