DOM—Node接口

DOM 概述

DOM

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

瀏覽器會(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 只是一個(gè)接口規(guī)范压固,可以用各種語言實(shí)現(xiàn)拦键。所以嚴(yán)格地說,DOM 不是 JavaScript 語法的一部分,但是 DOM 操作是 JavaScript 最常見的任務(wù),離開了 DOM,JavaScript 就無法控制網(wǎng)頁。另一方面,JavaScript 也是最常用于 DOM 操作的語言。

節(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)
  • DocumentTypedoctype標(biāo)簽(比如<!DOCTYPE html>
  • Element:網(wǎng)頁的各種HTML標(biāo)簽(比如<body><a>等)
  • Attribute:網(wǎng)頁元素的屬性(比如class="right"
  • Text:標(biāo)簽之間或標(biāo)簽包含的文本
  • Comment:注釋
  • DocumentFragment:文檔的片段

瀏覽器提供一個(gè)原生的節(jié)點(diǎn)對(duì)象Node屈溉,上面這七種節(jié)點(diǎn)都繼承了Node椰于,因此具有一些共同的屬性和方法。

節(jié)點(diǎn)樹

一個(gè)文檔的所有節(jié)點(diǎn)镀娶,按照所在的層級(jí)儿奶,可以抽象成一種樹狀結(jié)構(gòu)瓤鼻。這種樹狀結(jié)構(gòu)就是 DOM 樹秸妥。它有一個(gè)頂層節(jié)點(diǎn)檩禾,下一層都是頂層節(jié)點(diǎn)的子節(jié)點(diǎn)侨核,然后子節(jié)點(diǎn)又有自己的子節(jié)點(diǎn),就這樣層層衍生出一個(gè)金字塔結(jié)構(gòu),倒過來就像一棵樹瞻赶。

瀏覽器原生提供document節(jié)點(diǎn)穆咐,代表整個(gè)文檔拍柒。
文檔的第一層有兩個(gè)節(jié)點(diǎn),第一個(gè)是文檔類型節(jié)點(diǎn)(<!doctype html>),第二個(gè)是 HTML 網(wǎng)頁的頂層容器標(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),其他節(jié)點(diǎn)都有三種層級(jí)關(guān)系。

  • 父節(jié)點(diǎn)關(guān)系(parentNode):直接的那個(gè)上級(jí)節(jié)點(diǎn)
  • 子節(jié)點(diǎn)關(guān)系(childNodes):直接的下級(jí)節(jié)點(diǎn)
  • 同級(jí)節(jié)點(diǎn)關(guān)系(sibling):擁有同一個(gè)父節(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))屬性宋舷。

Node 接口

所有DOM節(jié)點(diǎn)對(duì)象都繼承了Node接口喇聊,擁有一些共同的屬性和方法腕柜。這是DOM操作的基礎(chǔ)。

屬性

Node.prototype.nodeType

nodeType屬性返回一個(gè)整數(shù)值盏缤,表示節(jié)點(diǎn)的類型砰蠢。

document.nodeType // 9

Node對(duì)象定義了幾個(gè)常量,對(duì)應(yīng)這些類型值唉铜。

document.nodeType === Node.DOCUMENT_NODE // true

上面代碼中台舱,文檔節(jié)點(diǎn)的nodeType屬性等于常量Node.DOCUMENT_NODE

不同節(jié)點(diǎn)的nodeType屬性值和對(duì)應(yīng)的常量如下潭流。

  • 文檔節(jié)點(diǎn)(document):9竞惋,對(duì)應(yīng)常量Node.DOCUMENT_NODE
  • 元素節(jié)點(diǎn)(element):1,對(duì)應(yīng)常量Node.ELEMENT_NODE
  • 屬性節(jié)點(diǎn)(attr):2灰嫉,對(duì)應(yīng)常量Node.ATTRIBUTE_NODE
  • 文本節(jié)點(diǎn)(text):3拆宛,對(duì)應(yīng)常量Node.TEXT_NODE
  • 文檔片斷節(jié)點(diǎn)(DocumentFragment):11,對(duì)應(yīng)常量Node.DOCUMENT_FRAGMENT_NODE
  • 文檔類型節(jié)點(diǎn)(DocumentType):10讼撒,對(duì)應(yīng)常量Node.DOCUMENT_TYPE_NODE
  • 注釋節(jié)點(diǎn)(Comment):8浑厚,對(duì)應(yīng)常量Node.COMMENT_NODE

確定節(jié)點(diǎn)類型時(shí),使用nodeType屬性是常用方法椿肩。

var node = document.documentElement.firstChild;
if (node.nodeType === Node.ELEMENT_NODE) {
  console.log('該節(jié)點(diǎn)是元素節(jié)點(diǎn)');
}
Node.prototype.nodeName

nodeName屬性返回節(jié)點(diǎn)的名稱瞻颂。

// <div id="d1">hello world</div>
var div = document.getElementById('d1');
div.nodeName // "DIV"

上面代碼中,元素節(jié)點(diǎn)<div>nodeName屬性就是大寫的標(biāo)簽名DIV郑象。

不同節(jié)點(diǎn)的nodeName屬性值如下贡这。

  • 文檔節(jié)點(diǎn)(document):#document
  • 元素節(jié)點(diǎn)(element):大寫的標(biāo)簽名
  • 屬性節(jié)點(diǎn)(attr):屬性的名稱
  • 文本節(jié)點(diǎn)(text):#text
  • 文檔片斷節(jié)點(diǎn)(DocumentFragment):#document-fragment
  • 文檔類型節(jié)點(diǎn)(DocumentType):文檔的類型
  • 注釋節(jié)點(diǎn)(Comment):#comment
Node.prototype.nodeValue

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

只有文本節(jié)點(diǎn)(text)、注釋節(jié)點(diǎn)(comment)和屬性節(jié)點(diǎn)(attr)有文本值击奶,因此這三類節(jié)點(diǎn)的nodeValue可以返回結(jié)果辈双,其他類型的節(jié)點(diǎn)一律返回null。同樣的柜砾,也只有這三類節(jié)點(diǎn)可以設(shè)置nodeValue屬性的值湃望,其他類型的節(jié)點(diǎn)設(shè)置無效。

// HTML 代碼如下
// <div id="d1">hello world</div>
var div = document.getElementById('d1');
div.nodeValue // null
div.firstChild.nodeValue // "hello world"

上面代碼中,div是元素節(jié)點(diǎn)证芭,nodeValue屬性返回null瞳浦。div.firstChild是文本節(jié)點(diǎn),所以可以返回文本值废士。

Node.prototype.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ì)于文本節(jié)點(diǎn)(text)、注釋節(jié)點(diǎn)(comment)和屬性節(jié)點(diǎn)(attr)赃磨,textContent屬性的值與nodeValue屬性相同筝家。對(duì)于其他類型的節(jié)點(diǎn),該屬性會(huì)將每個(gè)子節(jié)點(diǎn)(不包括注釋節(jié)點(diǎn))的內(nèi)容連接在一起返回邻辉。如果一個(gè)節(jié)點(diǎn)沒有子節(jié)點(diǎn)溪王,則返回空字符串。

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

Node.prototype.baseURI

baseURI屬性返回一個(gè)字符串吱瘩,表示當(dāng)前網(wǎng)頁的絕對(duì)路徑道伟。瀏覽器根據(jù)這個(gè)屬性,計(jì)算網(wǎng)頁上的相對(duì)路徑的 URL使碾。該屬性為只讀蜜徽。

// 當(dāng)前網(wǎng)頁的網(wǎng)址為
// http://www.example.com/index.html
document.baseURI
// "http://www.example.com/index.html"

如果無法讀到網(wǎng)頁的 URL,baseURI屬性返回null票摇。

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

<base >

設(shè)置了以后矢门,baseURI屬性就返回<base>標(biāo)簽設(shè)置的值盆色。

Node.prototype.ownerDocument

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

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

document對(duì)象本身的ownerDocument屬性隔躲,返回null缕允。

Node.prototype.nextSibling

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

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

d1.nextSibling === d2 // true

注意教届,該屬性還包括文本節(jié)點(diǎn)和注釋節(jié)點(diǎn)响鹃。因此如果當(dāng)前節(jié)點(diǎn)后面有空格,該屬性會(huì)返回一個(gè)文本節(jié)點(diǎn)案训,內(nèi)容為空格买置。

nextSibling屬性可以用來遍歷所有子節(jié)點(diǎn)。

var el = document.getElementById('div1').firstChild;

while (el !== null) {
  console.log(el.nodeName);
  el = el.nextSibling;
}

上面代碼遍歷div1節(jié)點(diǎn)的所有子節(jié)點(diǎn)强霎。

Node.prototype.previousSibling

previousSibling屬性返回當(dāng)前節(jié)點(diǎn)前面的忿项、距離最近的一個(gè)同級(jí)節(jié)點(diǎn)。如果當(dāng)前節(jié)點(diǎn)前面沒有同級(jí)節(jié)點(diǎn)城舞,則返回null轩触。

// <div id="d1">hello</div><div id="d2">world</div>
var d1 = document.getElementById('d1');
var d2 = document.getElementById('d2');

d2.previousSibling === d1 // true

注意,該屬性還包括文本節(jié)點(diǎn)和注釋節(jié)點(diǎn)家夺。因此如果當(dāng)前節(jié)點(diǎn)前面有空格脱柱,該屬性會(huì)返回一個(gè)文本節(jié)點(diǎn),內(nèi)容為空格拉馋。

Node.prototype.parentNode

parentNode屬性返回當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn)榨为。對(duì)于一個(gè)節(jié)點(diǎn)來說,它的父節(jié)點(diǎn)只可能是三種類型:元素節(jié)點(diǎn)(element)煌茴、文檔節(jié)點(diǎn)(document)和文檔片段節(jié)點(diǎn)(documentfragment)随闺。

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

上面代碼中,通過node.parentNode屬性將node節(jié)點(diǎn)從文檔里面移除蔓腐。

文檔節(jié)點(diǎn)(document)和文檔片段節(jié)點(diǎn)(documentfragment)的父節(jié)點(diǎn)都是null矩乐。另外,對(duì)于那些生成后還沒插入 DOM 樹的節(jié)點(diǎn)合住,父節(jié)點(diǎn)也是null绰精。

Node.prototype.parentElement

parentElement屬性返回當(dāng)前節(jié)點(diǎn)的父元素節(jié)點(diǎn)。如果當(dāng)前節(jié)點(diǎn)沒有父節(jié)點(diǎn)透葛,或者父節(jié)點(diǎn)類型不是元素節(jié)點(diǎn)笨使,則返回null

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

由于父節(jié)點(diǎn)只可能是三種類型:元素節(jié)點(diǎn)僚害、文檔節(jié)點(diǎn)(document)和文檔片段節(jié)點(diǎn)(documentfragment)硫椰。parentElement屬性相當(dāng)于把后兩種父節(jié)點(diǎn)都排除了繁调。

Node.prototype.firstChild,Node.prototype.lastChild

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

// <p id="p1"><span>First span</span></p>
var p1 = document.getElementById('p1');
p1.firstChild.nodeName // "SPAN"

注意奕翔,firstChild返回的除了元素節(jié)點(diǎn)裕寨,還可能是文本節(jié)點(diǎn)或注釋節(jié)點(diǎn)。

// <p id="p1">
//   <span>First span</span>
//  </p>
var p1 = document.getElementById('p1');
p1.firstChild.nodeName // "#text"

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

lastChild屬性返回當(dāng)前節(jié)點(diǎn)的最后一個(gè)子節(jié)點(diǎn)驾窟,如果當(dāng)前節(jié)點(diǎn)沒有子節(jié)點(diǎn)庆猫,則返回null。用法與firstChild屬性相同绅络。

Node.prototype.childNodes

childNodes屬性返回一個(gè)類似數(shù)組的對(duì)象(NodeList集合)月培,成員包括當(dāng)前節(jié)點(diǎn)的所有子節(jié)點(diǎn)。

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

使用該屬性恩急,可以遍歷某個(gè)節(jié)點(diǎn)的所有子節(jié)點(diǎn)杉畜。

var div = document.getElementById('div1');
var children = div.childNodes;

for (var i = 0; i < children.length; i++) {
  // ...
}

文檔節(jié)點(diǎn)(document)就有兩個(gè)子節(jié)點(diǎn):文檔類型節(jié)點(diǎn)(docType)和HTML根元素節(jié)點(diǎn)。

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

上面代碼中衷恭,文檔節(jié)點(diǎn)的第一個(gè)子節(jié)點(diǎn)的類型是10(即文檔類型節(jié)點(diǎn))寻行,第二個(gè)子節(jié)點(diǎn)的類型是1(即元素節(jié)點(diǎn))。

注意匾荆,除了元素節(jié)點(diǎn)拌蜘,childNodes屬性的返回值還包括文本節(jié)點(diǎn)和注釋節(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é)果之中举娩。

Node.prototype.isConnected

isConnected屬性返回一個(gè)布爾值,表示當(dāng)前節(jié)點(diǎn)是否在文檔之中构罗。

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

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

方法

Node.prototype.appendChild()

appendChild()方法接受一個(gè)節(jié)點(diǎn)對(duì)象作為參數(shù)铜涉,將其作為最后一個(gè)子節(jié)點(diǎn),插入當(dāng)前節(jié)點(diǎn)遂唧。該方法的返回值就是插入文檔的子節(jié)點(diǎn)芙代。

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

上面代碼新建一個(gè)<p>節(jié)點(diǎn),將其插入document.body的尾部盖彭。

如果參數(shù)節(jié)點(diǎn)是 DOM 已經(jīng)存在的節(jié)點(diǎn)纹烹,appendChild()方法會(huì)將其從原來的位置页滚,移動(dòng)到新位置。

var div = document.getElementById('myDiv');
document.body.appendChild(div);

上面代碼中铺呵,插入的是一個(gè)已經(jīng)存在的節(jié)點(diǎn)myDiv裹驰,結(jié)果就是該節(jié)點(diǎn)會(huì)從原來的位置,移動(dòng)到document.body的尾部片挂。

如果appendChild()方法的參數(shù)是DocumentFragment節(jié)點(diǎn)幻林,那么插入的是DocumentFragment的所有子節(jié)點(diǎn),而不是DocumentFragment節(jié)點(diǎn)本身音念。返回值是一個(gè)空的DocumentFragment節(jié)點(diǎn)滋将。

Node.prototype.hasChildNodes()

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

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

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

注意,子節(jié)點(diǎn)包括所有類型的節(jié)點(diǎn)父丰,并不僅僅是元素節(jié)點(diǎn)肝谭。哪怕節(jié)點(diǎn)只包含一個(gè)空格,hasChildNodes方法也會(huì)返回true蛾扇。

判斷一個(gè)節(jié)點(diǎn)有沒有子節(jié)點(diǎn)攘烛,有許多種方法,下面是其中的三種镀首。

  • node.hasChildNodes()
  • node.firstChild !== null
  • node.childNodes && node.childNodes.length > 0

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

function DOMComb(parent, callback) {
  if (parent.hasChildNodes()) {
    for (var node = parent.firstChild; node; node = node.nextSibling) {
      DOMComb(node, callback);
    }
  }
  callback(parent);
}

// 用法
DOMComb(document.body, console.log)

上面代碼中更哄,DOMComb函數(shù)的第一個(gè)參數(shù)是某個(gè)指定的節(jié)點(diǎn)芋齿,第二個(gè)參數(shù)是回調(diào)函數(shù)。這個(gè)回調(diào)函數(shù)會(huì)依次作用于指定節(jié)點(diǎn)成翩,以及指定節(jié)點(diǎn)的所有后代節(jié)點(diǎn)觅捆。

Node.prototype.cloneNode()

cloneNode方法用于克隆一個(gè)節(jié)點(diǎn)。它接受一個(gè)布爾值作為參數(shù)麻敌,表示是否同時(shí)克隆子節(jié)點(diǎn)栅炒。它的返回值是一個(gè)克隆出來的新節(jié)點(diǎn)。

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

該方法有一些使用注意點(diǎn)术羔。

  1. 克隆一個(gè)節(jié)點(diǎn)赢赊,會(huì)拷貝該節(jié)點(diǎn)的所有屬性,但是會(huì)喪失addEventListener方法和on-屬性(即node.onclick = fn)级历,添加在這個(gè)節(jié)點(diǎn)上的事件回調(diào)函數(shù)释移。
  2. 該方法返回的節(jié)點(diǎn)不在文檔之中,即沒有任何父節(jié)點(diǎn)寥殖,必須使用諸如Node.appendChild這樣的方法添加到文檔之中秀鞭。
  3. 克隆一個(gè)節(jié)點(diǎn)之后趋观,DOM 有可能出現(xiàn)兩個(gè)有相同id屬性(即id="xxx")的網(wǎng)頁元素,這時(shí)應(yīng)該修改其中一個(gè)元素的id屬性锋边。如果原節(jié)點(diǎn)有name屬性皱坛,可能也需要修改。
Node.prototype.insertBefore()

insertBefore方法用于將某個(gè)節(jié)點(diǎn)插入父節(jié)點(diǎn)內(nèi)部的指定位置豆巨。

var insertedNode = parentNode.insertBefore(newNode, referenceNode);

insertBefore方法接受兩個(gè)參數(shù)剩辟,第一個(gè)參數(shù)是所要插入的節(jié)點(diǎn)newNode,第二個(gè)參數(shù)是父節(jié)點(diǎn)parentNode內(nèi)部的一個(gè)子節(jié)點(diǎn)referenceNode往扔。newNode將插在referenceNode這個(gè)子節(jié)點(diǎn)的前面贩猎。返回值是插入的新節(jié)點(diǎn)newNode

var p = document.createElement('p');
document.body.insertBefore(p, document.body.firstChild);

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

var p = document.createElement('p');
document.body.insertBefore(p, null);

上面代碼中蝗罗,p將成為document.body的最后一個(gè)子節(jié)點(diǎn)艇棕。這也說明insertBefore的第二個(gè)參數(shù)不能省略。

注意串塑,如果所要插入的節(jié)點(diǎn)是當(dāng)前 DOM 現(xiàn)有的節(jié)點(diǎn)沼琉,則該節(jié)點(diǎn)將從原有的位置移除,插入新的位置桩匪。

由于不存在insertAfter方法打瘪,如果新節(jié)點(diǎn)要插在父節(jié)點(diǎn)的某個(gè)子節(jié)點(diǎn)后面,可以用insertBefore方法結(jié)合nextSibling屬性模擬傻昙。

parent.insertBefore(s1, s2.nextSibling);

上面代碼中闺骚,parent是父節(jié)點(diǎn),s1是一個(gè)全新的節(jié)點(diǎn)妆档,s2是可以將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的后面乳绕。

如果要插入的節(jié)點(diǎn)是DocumentFragment類型,那么插入的將是DocumentFragment的所有子節(jié)點(diǎn)逼纸,而不是DocumentFragment節(jié)點(diǎn)本身洋措。返回值將是一個(gè)空的DocumentFragment節(jié)點(diǎn)。

Node.prototype.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);

上面代碼移除了divA節(jié)點(diǎn)。注意滓鸠,這個(gè)方法是在divA的父節(jié)點(diǎn)上調(diào)用的雁乡,不是在divA上調(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)下面楔敌。

如果參數(shù)節(jié)點(diǎn)不是當(dāng)前節(jié)點(diǎn)的子節(jié)點(diǎn)啤挎,removeChild方法將報(bào)錯(cuò)。

Node.prototype.replaceChild()

replaceChild方法用于將一個(gè)新的節(jié)點(diǎn)卵凑,替換當(dāng)前節(jié)點(diǎn)的某一個(gè)子節(jié)點(diǎn)庆聘。

var replacedNode = parentNode.replaceChild(newChild, oldChild);

上面代碼中,replaceChild方法接受兩個(gè)參數(shù)氛谜,第一個(gè)參數(shù)newChild是用來替換的新節(jié)點(diǎn),第二個(gè)參數(shù)oldChild是將要替換走的子節(jié)點(diǎn)区端。返回值是替換走的那個(gè)節(jié)點(diǎn)oldChild值漫。

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

contains方法返回一個(gè)布爾值,表示參數(shù)節(jié)點(diǎn)是否滿足以下三個(gè)條件之一织盼。

  • 參數(shù)節(jié)點(diǎn)為當(dāng)前節(jié)點(diǎn)杨何。
  • 參數(shù)節(jié)點(diǎn)為當(dāng)前節(jié)點(diǎn)的子節(jié)點(diǎn)。
  • 參數(shù)節(jié)點(diǎn)為當(dāng)前節(jié)點(diǎn)的后代節(jié)點(diǎn)沥邻。
document.body.contains(node)

上面代碼檢查參數(shù)節(jié)點(diǎn)node危虱,是否包含在當(dāng)前文檔之中。

注意唐全,當(dāng)前節(jié)點(diǎn)傳入contains方法埃跷,返回true

nodeA.contains(nodeA) // true
Node.prototype.compareDocumentPosition()

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

二進(jìn)制值 十進(jìn)制值 含義
000000 0 兩個(gè)節(jié)點(diǎn)相同
000001 1 兩個(gè)節(jié)點(diǎn)不在同一個(gè)文檔(即有一個(gè)節(jié)點(diǎn)不在當(dāng)前文檔)
000010 2 參數(shù)節(jié)點(diǎn)在當(dāng)前節(jié)點(diǎn)的前面
000100 4 參數(shù)節(jié)點(diǎn)在當(dāng)前節(jié)點(diǎn)的后面
001000 8 參數(shù)節(jié)點(diǎn)包含當(dāng)前節(jié)點(diǎn)
010000 16 當(dāng)前節(jié)點(diǎn)包含參數(shù)節(jié)點(diǎn)
100000 32 瀏覽器內(nèi)部使用
// HTML 代碼如下
// <div id="mydiv">
//   <form><input id="test" /></form>
// </div>

var div = document.getElementById('mydiv');
var input = document.getElementById('test');

div.compareDocumentPosition(input) // 20
input.compareDocumentPosition(div) // 10

上面代碼中剪勿,節(jié)點(diǎn)div包含節(jié)點(diǎn)input(二進(jìn)制010000),而且節(jié)點(diǎn)input在節(jié)點(diǎn)div的后面(二進(jìn)制000100)方庭,所以第一個(gè)compareDocumentPosition方法返回20(二進(jìn)制010100厕吉,即010000 + 000100)酱固,第二個(gè)compareDocumentPosition方法返回10(二進(jìn)制001010)。

由于compareDocumentPosition返回值的含義头朱,定義在每一個(gè)比特位上卦碾,所以如果要檢查某一種特定的含義,就需要使用比特位運(yùn)算符钧汹。

var head = document.head;
var body = document.body;
if (head.compareDocumentPosition(body) & 4) {
  console.log('文檔結(jié)構(gòu)正確');
} else {
  console.log('<body> 不能在 <head> 前面');
}

上面代碼中据某,compareDocumentPosition的返回值與4(又稱掩碼)進(jìn)行與運(yùn)算(&),得到一個(gè)布爾值寄纵,表示<head>是否在<body>前面鳖敷。

Node.prototype.isEqualNode(),Node.prototype.isSameNode()

isEqualNode方法返回一個(gè)布爾值程拭,用于檢查兩個(gè)節(jié)點(diǎn)是否相等定踱。所謂相等的節(jié)點(diǎn),指的是兩個(gè)節(jié)點(diǎn)的類型相同恃鞋、屬性相同崖媚、子節(jié)點(diǎn)相同。

var p1 = document.createElement('p');
var p2 = document.createElement('p');

p1.isEqualNode(p2) // true

isSameNode方法返回一個(gè)布爾值恤浪,表示兩個(gè)節(jié)點(diǎn)是否為同一個(gè)節(jié)點(diǎn)畅哑。

var p1 = document.createElement('p');
var p2 = document.createElement('p');

p1.isSameNode(p2) // false
p1.isSameNode(p1) // true
Node.prototype.normalize()

normalize方法用于清理當(dāng)前節(jié)點(diǎn)內(nèi)部的所有文本節(jié)點(diǎn)(text)。它會(huì)去除空的文本節(jié)點(diǎn)水由,并且將毗鄰的文本節(jié)點(diǎn)合并成一個(gè)荠呐,也就是說不存在空的文本節(jié)點(diǎn),以及毗鄰的文本節(jié)點(diǎn)砂客。

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è)毗鄰的文本子節(jié)點(diǎn)。使用normalize方法之后鞠值,兩個(gè)文本子節(jié)點(diǎn)被合并成一個(gè)媚创。

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

Node.prototype.getRootNode()

getRootNode()方法返回當(dāng)前節(jié)點(diǎn)所在文檔的根節(jié)點(diǎn)document彤恶,與ownerDocument屬性的作用相同钞钙。

document.body.firstChild.getRootNode() === document
// true
document.body.firstChild.getRootNode() === document.body.firstChild.ownerDocument
// true

該方法可用于document節(jié)點(diǎn)自身,這一點(diǎn)與document.ownerDocument不同声离。

document.getRootNode() // document
document.ownerDocument // null
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末歇竟,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子抵恋,更是在濱河造成了極大的恐慌焕议,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,000評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異盅安,居然都是意外死亡唤锉,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門别瞭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來窿祥,“玉大人,你說我怎么就攤上這事蝙寨∩柜茫” “怎么了?”我有些...
    開封第一講書人閱讀 168,561評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵墙歪,是天一觀的道長(zhǎng)听系。 經(jīng)常有香客問我,道長(zhǎng)虹菲,這世上最難降的妖魔是什么靠胜? 我笑而不...
    開封第一講書人閱讀 59,782評(píng)論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮毕源,結(jié)果婚禮上浪漠,老公的妹妹穿的比我還像新娘。我一直安慰自己霎褐,他們只是感情好址愿,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,798評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著冻璃,像睡著了一般响谓。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上俱饿,一...
    開封第一講書人閱讀 52,394評(píng)論 1 310
  • 那天歌粥,我揣著相機(jī)與錄音塌忽,去河邊找鬼拍埠。 笑死,一個(gè)胖子當(dāng)著我的面吹牛土居,可吹牛的內(nèi)容都是我干的枣购。 我是一名探鬼主播,決...
    沈念sama閱讀 40,952評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼擦耀,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼棉圈!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起眷蜓,我...
    開封第一講書人閱讀 39,852評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤分瘾,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后吁系,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體德召,經(jīng)...
    沈念sama閱讀 46,409評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡白魂,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,483評(píng)論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了上岗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片福荸。...
    茶點(diǎn)故事閱讀 40,615評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖肴掷,靈堂內(nèi)的尸體忽然破棺而出敬锐,到底是詐尸還是另有隱情,我是刑警寧澤呆瞻,帶...
    沈念sama閱讀 36,303評(píng)論 5 350
  • 正文 年R本政府宣布台夺,位于F島的核電站,受9級(jí)特大地震影響栋烤,放射性物質(zhì)發(fā)生泄漏谒养。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,979評(píng)論 3 334
  • 文/蒙蒙 一明郭、第九天 我趴在偏房一處隱蔽的房頂上張望买窟。 院中可真熱鬧,春花似錦薯定、人聲如沸始绍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽亏推。三九已至,卻和暖如春年堆,著一層夾襖步出監(jiān)牢的瞬間吞杭,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工变丧, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留芽狗,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,041評(píng)論 3 377
  • 正文 我出身青樓痒蓬,卻偏偏與公主長(zhǎng)得像童擎,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子攻晒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,630評(píng)論 2 359

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

  • ??DOM(文檔對(duì)象模型)是針對(duì) HTML 和 XML 文檔的一個(gè) API(應(yīng)用程序編程接口)鲁捏。 ??DOM 描繪...
    霜天曉閱讀 3,655評(píng)論 0 7
  • 前言:盡管現(xiàn)在有很多優(yōu)秀的框架芯砸,大大簡(jiǎn)化了我們的DOM操作,但是我們?nèi)匀灰獙W(xué)好DOM知識(shí)來寫原生JS,從根本上去理...
    長(zhǎng)鯨向南閱讀 1,885評(píng)論 0 0
  • 一假丧、基本概念 1.1末购、DOM DOM是JS操作網(wǎng)頁的接口,全稱為“文檔對(duì)象模型”(Document Object ...
    周花花啊閱讀 3,194評(píng)論 0 6
  • 基本概念 DOM DOM 是 JavaScript 操作網(wǎng)頁的接口虎谢,全稱為“文檔對(duì)象模型”(Document Ob...
    許先生__閱讀 865評(píng)論 0 1
  • 第3章 基本概念 3.1 語法 3.2 關(guān)鍵字和保留字 3.3 變量 3.4 數(shù)據(jù)類型 5種簡(jiǎn)單數(shù)據(jù)類型:Unde...
    RickCole閱讀 5,130評(píng)論 0 21