通過上一節的學習,對JavaScript中的DOM有了一定的認識。雖然對DOM中相關的知識點有一定的概念,但還是缺乏對DOM的實際操作。如果你仔細閱讀過上一篇文章的話,你應該會發現,當時也提到了一些DOM操作相關的東西,比如,DOM的增、刪、改和查等。那麼今天我們就來看看這些方面的東西。
先來看DOM操作中的增。其主要分為兩個部分:新創建節點和插入節點。
常用的DOM節點創建有關的API接口主要有:
document.createElement
:創建指定的HTML元素或一個HTMLUnknownElement
document.createTextNode
:創建文本節點document.createDocumentFrame
:創建文檔片段document.createAttribute
:創建節點屬性document.adoptNode
:從外部文檔中獲取一個節點document.importNode
:拷貝外部文檔的一個節點node.cloneNode
:克隆節點document.createElement
document.createElement(tagName[, options])
是其中最常用的DOM API之一,主要用來創建由標籤名稱(tagName
)指定的HTML元素,如果標籤名稱不是一個有效的HTML元素,將會創建一個HTMLUnknownElement
對象。來看一個簡單的示例:
let newEle = document.createElement('div');
let newContent = document.createTextNode('我是一個新創建的div元素')
newEle.appendChild(newContent)
document.body.appendChild(newEle)
注意,通過document.createElement
創建的元素並不屬於document
對象,它只是創建出來,並未添加到HTML文檔中,需要調用appendChild()
或insertBefore()
等方法將其添加到HTML文檔中。
如果你對
HTMLUnknownElement
從未接觸,建議你有空花點時間閱讀@張鑫旭老濕的《》和@米粽大大翻譯的《Custom Elements》。
document.createTextNode
document.createTextNode(text)
創建一個文本節點,參數text
為文本節點的內容。比如:
let newContent = document.createTextNode('我是一個新創建的div元素')
newEle.appendChild(newContent)
創建了一個文本節點newContent
,然後把這個新創建的文本節點通過appendChild()
方法,將其插入到newEle
元素中,當作其內容。document.createTextNode(text)
方法返回的節點,被瀏覽器當作文本渲染,而不是當作HTML代碼渲染,因此會對HTML代碼進行轉義,可以用來展示用戶的輸入,避免XSS
攻擊。
function escapeUserInput(str) {
var div = document.createElement('div');
div.appendChild(document.createTextNode(str));
return div.innerHTML;
}
var userInput = '<p>危險內容</p>';
var template = '<div>' + escapeUserInput(userInput) + '</div>'
// 此時被轉義,危險內容不再危險
<div><p>危險內容</p></div>
但是,該方法不對單引號和雙引號轉義,因此用來為屬性賦值的時候,仍然會被 XSS
攻擊:
var userInput = '" onmouseover="console.log(\'危險操作\')" "';
var template = '<div color="' + escapeUserInput(userInput) + '">user set color</div>'
// 被注入一個 onmouseover 操作
<div color="" onmouseover="console.log('危險操作')" "">user set color</div>
其中XSS
攻擊屬於Web安全方面的知識了,不屬於這篇文章的範疇。如果你對XSS
相關的東西感興趣的話,可以看看下面幾篇文章:
document.createDocumentFragment
document.createDocumentFragment()
方法創建一個新空白的DocumentFragment
對象。
DocumentFragments是DOM節點。它們不是主DOM樹的一部分。通常的用例是創建文檔片段,將元素附加到文檔片段,然後將文檔片段附加到DOM樹。在DOM樹中,文檔片段被其所有的子元素代替。
因為文檔片段存在於內存中,並不在DOM樹中,所以將子元素插入到文檔片段時不會引起頁面回流(reflow
)(對元素位置和幾何上的計算)。因此,使用文檔片段document fragments 通常會起到優化性能的作用。
比如下面這個示例,給一個ul
添加10000
個li
,先用拼接字符串的方式來實現:
let start = Date.now()
let str = ''
let newUlEle = document.createElement('ul')
document.body.appendChild(newUlEle)
for (let i = 0; i < 10000; i++) {
str += '<li>第' + i + '個子節點</li>'
}
newUlEle.innerHTML = str
console.log('耗時' + (Date.now() - start) + 'ms');
多次刷新,可以看到創建10000
個li
時,渲染所需要的時間如下圖:
把上面的示例,換成append()
的方式,逐個添加對應的li
:
let start = Date.now()
let str = ''
let newUlEle = document.createElement('ul')
document.body.appendChild(newUlEle)
for (let i = 0; i < 10000; i++) {
let liEle = document.createElement('li')
liEle.textContent = '第' + i + '個子節點'
newUlEle.appendChild(liEle)
}
console.log('耗時:' + (Date.now() - start) + 'ms')
這種方法所費時間如下圖:
都說第二種方法要比第一種方法耗時,看上去有點像。接下來再來看createDocumentFragment
的方法。可以預見的是,這種方法肯定比第二種強,但應該沒有第一種快:
let start = Date.now()
let str = ''
let newUlEle = document.createElement('ul')
document.body.appendChild(newUlEle)
let fragment = document.createDocumentFragment()
for (let i = 0; i < 10000; i++) {
let liEle = document.createElement('li')
liEle.textContent = '第' + i + '個子節點'
fragment.appendChild(liEle)
}
newUlEle.appendChild(fragment)
console.log('耗時:' + (Date.now() - start) + 'ms')
document.createAttribute()
document.createAttribute(attrName)
方法創建並返回一個新的屬性節點。這個方法不是很常用,因為添加屬性通常使用node.setAttribute()
。
let node = document.getElementById('content')
let attr = document.createAttribute('title')
attr.nodeValue = 'Hello JavaScript!'
node.setAttributeNode(attr)
上面的代碼會給div#content
的元素添加一個title
屬性,而且這個title
屬性的值為Hello JavaScript!
:
同樣的,document.createAttribute()
雖然創建了屬性節點,如果不通過setAttributeNode()
方法的話,創建的屬性的節點是不會運用到對應的元素節點上的。該方法的返回值是一個Attr
類型的節點。借助nodeValue
給該節點賦值,然後給該屬性節點設置對應的屬性值。等同的效果,常常使用setAttribute()
方法來替代該方法。後續我們會介紹到setAttribute()
方法相關的知識。
document.adoptNode
document.adoptNode(externalNode)
從其他的 document
中獲取一個節點(externalNode
),並將該節點以及它的所有子節點從原文檔刪除, 並且它的 ownerDocument
屬性會變成當前的 document
。之後你可以把這個節點插入到當前文檔中,不常用,瞭解即可。
// 該函數用來從本文檔的第一個 iframe 中獲取第一個 element 元素,
// 並插入到當前文檔樹中
function getEle(){
var iframe = document.getElementsByTagName("iframe")[0],
ele = iframe.contentWindow.document.body.firstElementChild;
if(ele){
document.body.appendChild(document.adoptNode(ele))
}else{
alert("沒有更多元素了")
}
}
document.getElementById("move").onclick = getEle
注意,該方法在同一 document
下的不同兩個元素中也可以使用,可以實現從左邊欄列表中選取某些元素加載到右邊欄的功能。如果節點資源來自不同的源的時候,調用 adoptNode
可能會失敗。
有些情況下,將外部文檔的節點插入當前文檔之前,你需要使用 document.importNode()
從外部文檔導入源節點,瞭解更多細節。
document.importNode
document.importNode(externalNode, deep)
這個接口也不常用,作用是拷貝外部文檔的一個節點(externalNode
)。deep
表明是否要導入節點的後代節點,默認為 false
不導入後代節點。
var iframe = document.getElementsByTagName("iframe")[0];
var oldNode = iframe.contentDocument.getElementById("myNode");
var newNode = document.importNode(oldNode, true);
document.getElementById("container").appendChild(newNode);
注意,這個方法僅拷貝節點,此時,節點存在於內存中,還需要插入當前文檔中才能顯示。
node.cloneNode
node.cloneNode(deep)
方法返回該節點的一個副本,deep
可選,表明是否採用深度克隆,如果為true
,則該節點的所有後代節點也都會被克隆,否則,只克隆該節點本身。
let node = document.getElementById('content')
let cloneNode = node.cloneNode(true)
cloneNode.id = "newId"
document.body.appendChild(cloneNode)
上面的這個小示例,克隆了div#content
以及其所有後代節點,並且把新克隆的元素的id
賦值為newId
,然後再把新克隆出來的所有節點重新插入body
中。最終的效果如下:
上面的示例,演示了,使用node.cloneNode(true)
可以克隆節點的所有後代節點以及其所有屬性。那麼對於綁定的事件是否也能被克隆呢?還是通過示例來驗證一下,看看事件是否也會被克隆。
<div id="box">
<button id="clone" onclick="console.log('Click Clone Button')">Clone Me!</button>
</div>
<div id="new"></div>
// cloneNode
let btn = document.getElementById('clone')
let box = document.getElementById('box')
let newDiv = document.getElementById('new')
newDiv.appendChild(box.cloneNode(true))
上面的示例使用了內聯方式直接把事件寫在HTML標籤上。從結果我們可以看到綁定在HTML標籤上的事件也被克隆了。
接下來在上例的基礎上做一下調整,把內聯方式換成綁定在節點對象上的事件:
let btn = document.getElementById('clone')
let box = document.getElementById('box')
let newDiv = document.getElementById('new')
btn.onclick = function () {
console.log('click clone')
}
newDiv.appendChild(box.cloneNode(true))
從結果可以看出,綁定在節點對象的事件在克隆的副本並不包含事件處理程序。接著再做一下調整,使用addEventListener()
方法把事件添加在節點上:
btn.addEventListener('click', function (){
console.log('Click clone!')
})
得到的效果其實和上圖是一樣的。也就是說,克隆的時候,addEventListener()
綁定的事件並沒有被克隆。
從上面的示例可以證明,副本節點只能綁定使用內聯方式綁定的事件處理函數。簡單點說,只有內聯在HTML元素的事件,才會被
cloneNode()
克隆。
注意,這個拷貝的節點並不在文檔中,需要自行添加到文檔中。同時拷貝的節點有可能會導致節點的的 id
屬性重複,最好修改新節點的 id
,而 name
屬性也可能重複,自行決定是否需要修改。
DOM節點修改有關的API有:
node.appendChild()
:插入一個新節點node.insertBefore()
:插入一個新節點node.removeChild()
:刪除一個節點node.replaceChild()
:替換一個節點其中node.appendChild
和node.insertBefore
屬於DOM增中的新節點插入,而removeChild
屬於DOM中的刪,replaceChild
屬於DOM中的改。這一節,咱們只先聊增這一部分,對於刪和改,我們後面會單獨介紹。
node.appendChild
parentNode.appendChild(child)
方法將一個節點child
添加到指定的父節點parentNode
的子節點列表的末尾。本方法返回值為要插入的這個節點。
let pEle = document.createElement('p')
pEle.textContent = '我是新添加的p元素'
document.body.appendChild(pEle)
上面的示例創建了一個新的段落元素pEle
,然後使用appendChild()
將這個新創建的元素添加到body
的最末尾。
使用appendChild()
方法的時候有一點需要注意。如果被插入的節點已經存在文檔樹中,則節點會被從原先的位置移除,並插入到新的位置。當然,被移動的元素被綁定的事件也會被同步過去,比如:
<div id="old">
<p id="move">我是一個段落元素</p>
</div>
<div id="new"></div>
<button id="btn">創建元素</button>
let pEle = document.getElementById('move')
let newEle = document.getElementById('new')
let btnEle = document.getElementById('btn')
pEle.addEventListener('click', function() {
console.log('click me!')
})
btnEle.addEventListener('click', function () {
pEle.textContent = '我是新添加的p元素'
newEle.appendChild(pEle)
})
如果要保留原來的這個子節點的位置,則可以用 Node.cloneNode
方法複製出一個節點的副本,然後再插入到新位置。這個方法只能將某個子節點插入到同一個文檔的其他位置,如果你想跨文檔插入,需要先調用document.importNode
方法。還有,如果appendChild()
方法的參數是DocumentFragment
節點,那麼插入的是DocumentFragment
的所有子節點,而不是DocumentFragment
節點本身。此時,返回值是一個空的DocumentFragment
節點。
node.insertBefore
parentNode.insertBefore(child, referenceNode)
方法將一個節點child
插入作為父節點parentNode
的一個子節點,並且位置在參考節點referenceNode
之前。
如果第二個參數referenceNode
為null
,則插入位置你父節點的末尾:
parentNode.insertBefore(node, null);
// 等價於
parentNode.appendChild(node);
注意,第二個參數為
null
時不能省略,否則會報錯。
來看一個小示例:
<div id="parent">
我是父節點
<p id="child">我是舊的子節點</p>
</div>
<button id="btn">插入節點</button>
let parentEle = document.getElementById('parent')
let childEle = document.getElementById('child')
let btnEle = document.getElementById('btn')
btnEle.addEventListener('click', function () {
let newEle = document.createElement('span')
newEle.textContent = '我是新添加節點的文本內容'
parentEle.insertBefore(newEle, childEle)
})
使用這個方法可以模擬prependChild
,產生類似於appendChild()
,但是將節點插入作為指定父節點的第一個子節點:
Node.prototype.prependChild = function (node) {
return this.insertBefore(node, this.firstChild)
}
let parentEle = document.getElementById('parent')
let btnEle = document.getElementById('btn')
btnEle.addEventListener('click', function () {
let newEle = document.createElement('p')
newEle.textContent = '我是新添加節點的文本內容'
parentEle.prependChild(newEle)
})
其實這個效果和前面的效果是類似的。同樣的,使用這個方法還可以模擬insertAfter
,將節點要插在父節點的某個子節點後面:
Node.prototype.insertAfter = function(node, referenceNode) {
return this.insertBefore(node, referenceNode.nextSibling);
}
和 appendChild
類似,如果插入的節點是文檔中已經存在的節點,則會移動該節點到指定位置,並且保留其綁定的事件。
DOM節點的刪除主要API是node.removeChild
。可以使用parentNode.removeChild(child)
刪除指定父節點parentNode
的一個子節點child
,並返回被刪除的節點。
這個方法是要在被刪除的節點的父節點上調用的,而不是在被刪除節點上調用的,如果參數節點不是當前節點的子節點,removeChild
方法將報錯:
// 通過 parentNode 屬性直接刪除自身
var node = document.getElementById('deleteDiv');
if (node.parentNode) {
node.parentNode.removeChild(node);
}
// 也可以封裝以下作為一個方法直接使用:
Node.prototype.remove = function(node) {
if (node.parentNode) {
return node.parentNode.removeChild(node);
}
throw new Error('Can not delete.');
}
node.remove();
使用這個方法也可以很簡單的模擬 removeAllChild
:
Node.prototype.removeAllChild = function() {
var deleteNode = []
while (this.firstChild) {
deleteNode.push(this.removeChild(this.firstChild));
}
return deleteNode;
}
被移除的這個子節點仍然存在於內存中,只是不在當前文檔的 DOM 中,仍然還可以被添加回文檔中。但是如果不使用一個變量保存這個節點的引用,被刪除的節點將不可達,會在某次垃圾回收被清除。
parentNode.replaceChild(newChild, oldChild)
方法用指定的節點newChild
替換當前節點parentNode
的一個子節點oldChild
,並返回被替換的節點oldChild
。
<div id="parent">
<p id="child">我是舊的第一個子節點</p>
</div>
<button id="btn">替換節點</button>
let parentEle = document.getElementById('parent')
let oldEle = document.getElementById('child')
let btnEle = document.getElementById('btn')
btnEle.addEventListener('click', function () {
let newEle = document.createElement('p')
newEle.setAttribute('id', 'newChild')
newEle.textContent = '我是新添加節點的文本內容'
parentEle.replaceChild(newEle, oldEle)
})
DOM中的節點操作對應的主要API有:
appendChild()
:用於向childNodes
列表的末尾添加一個節點。返回新增的節點。insertBefore()
:接收兩個參數:要插入的節點和作為參照的節點。插入節點後,被插入的節點會變成參照節點的前一個同胞節點。同時被方法返回。replaceChild()
:接收兩個參數:要插入的節點和要替換的節點。要替換的節點將由這個方法返回並從文檔樹中移除。同時由要插入的節點佔據其位置。removeChild()
:接收一個參數,即要移除的節點。返回被移除的節點。這四個方法都是操作的某個節點的子節點,也就是說,要使用這幾個方法必須先取得父節點。另外並不是所有節點都有子節點,如果在不支持子節點的節點上,調用了這些方法,將會導致錯誤。
DOM節點中的查主要包括:查找元素(類似於CSS中的選擇器)和節點查找。
先來看DOM中怎麼查找到元素,也就是說選擇到你想要的元素。在DOM中查找元素(選擇到想要的元素)對應的API主要有:
document.getElementById(id)
:匹配特定id
的元素document.getElementsByName(name)
:根據給定的name
返回一個在 (X)HTML document
的NodeList
集合document.getElementsByTagName(tagName)
:返回一個包括所有給定標籤名稱的元素的HTML集合HTMLCollection
document.getElementsByClassName(className)
:返回包含了所有指定類名的子元素的類數組對象document.querySelector(selector)
:返回文檔中與指定選擇器或選擇器組匹配的第一個Element
document.querySelectorAll(selector)
:返回與指定的選擇器組匹配的文檔中的元素列表。返回的對象是NodeList
假設我們有一個簡單的DOM文檔:
<div id="box">
<h3>Title</h3>
<ul class="list">
<li class="item">Item1</li>
<li class="item">Item2</li>
<li class="item">Item3</li>
<li class="item">Item4</li>
<li class="item">Item5</li>
</ul>
<p id="intro">Intro ...</p>
</div>
為了更好的說明前面的幾個API,後續中的示例,都會採用這個DOM結構。其對應的DOM樹不再繪製了。
document.getElementById(id)
document.getElementById(id)
返回的是一個Element對象,用來匹配文檔中指定的id
元素。如果沒有找到對應的元素,該方法會返回null
。另外,document.getElementById()
方法不會搜索不在文檔中的元素。當創建一個元素,並且分配id
後,必須要使用insertBefore
或其他類似的方法把元素插入到文檔之後才能使用document.getElementById()
獲取到。
來看一個示例:
let idEle = document.getElementById('intro')
let btnEle = document.getElementById('btn')
btnEle.addEventListener('click', function () {
console.log(`能匹配到的: ${idEle}`)
console.log(idEle)
let newEle = document.createElement('section')
newEle.id = 'main'
newEle.textContent = '我是新添加的元素'
console.log(`未插入到DOM的新元素newEle: ${document.getElementById('main')}`)
console.log(document.getElementById('main'))
let box = document.getElementById('box')
box.insertBefore(newEle, idEle)
console.log(`插入到DOM的新元素newEle: ${document.getElementById('main')}`)
console.log(document.getElementById('main'))
})
來看輸出的結果:
比如上面示例,通過document.getElementById()
之後,咱們獲取了DOM上的節點,這個時候可以對該節點做很多事情,比如查詢內容和屬性,或者其他任何操作,甚至可以刪除它,克隆它,或者將它移動到DOM樹的其它節點上。
注意,document.getElementById(id)
中的id
參數是有大小寫敏感的,所以document.getElementById('Intro')
無法獲取到元素<p id="intro">Intro ...</p>
。另外還有就是,如果文檔中有多個相同的id
(這種情形一般不存在)時,只會返回第一個。
document.getElementsByName(name)
document.getElementsByName(name)
將根據給定的name
返回一個在document
的節點列表集合。name
屬性只有在HTML文檔中可用。該方法返回的是一個NodeList
集合,這個集合包含name
屬性為指定值的所有元素,比如<meta>
、<object>
,甚至那些不支持name
屬性但是添加了name
自定義屬性的元素也包含其中。
該方法常用於取得單選按鈕。同樣也會返回HTMLCollection
對象。HTMLCollection
對象可以通過length
屬性訪問元素長度,通過[]
方括號語法訪問對象中的項。方括號中既可以是數字,也可以是字符串索引值。
document.getElementsByTagName(tagName)
document.getElementsByTagName(tagName)
將會返回一個包括所有給定標籤名稱tagName
的元素的HTML集合HTMLCollection
。整個文件結構都會被搜索,包括根節點。返回的HTML集合是動態的,意味著它可以自動更新來保持和DOM樹同步,而不用再次調用document.getElementsByTagName(tagName)
。
let liEle = document.getElementsByTagName('li')
let btnEle = document.getElementById('btn')
btnEle.addEventListener('click', function () {
console.log(`能匹配到的: ${liEle}`)
console.log(liEle.length)
Object.keys(liEle).forEach(key => {
console.log(key, liEle[key])
})
})
比如上面的示例,通過getElementsByTagName('li')
獲取了文檔中所有的<li>
元素。其開始於一個具體的父元素並且從它自上而下遞歸地在DOM樹中搜索符合標籤名稱參數的子元素。剛才也說了,其返回的是一個動態的HTMLCollection
對象。獲得這個對象之後,可以對其做一些遍歷操作。比如上面使用Object.keys()
遍歷出li
:
有關於JavaScript中對象遍歷相關的操作可以閱讀《如何遍歷JavaScript中對象屬性》和《對象屬性的枚舉》。
有一點需要注意,調用 getElementsByTagName()
的不是那個文件節點 document
,事實上是使用這個方法 element.getElementsByTagName()
。
document.getElementsByClassName(className)
document.getElementsByClassName(className)
返回一個包含了所有指定類名的子元素的類數組對象。當在document
對象上調用時,會搜索整個DOM文檔,包含根節點。你也可以在任意元素上調用getElementsByClassName()
方法,它將返回的是以當前元素為根節點,所有指定類名的子元素。
比如,獲取所有class
為item
的元素:
document.getElementsByClassName('item')
如果你想獲取多個class
的元素時,可以用空格來隔開,比如說,同時獲取所有class
同時包括btn
和btn-lg
的元素:
document.getElementsByClassName('btn btn-lg')
如果你想獲取某個元素的子節點中對應class
的元素時,你也可以像下面這樣操作:
document.getElementById('box').getElementsByClassName('item')
document.querySelector(selector)
document.querySelector(selector)
方法可以幫助你選擇一個HTML元素。如果選擇了多個HTML元素,其總是返回第一個元素。它看起來像這樣:
document.querySelector('li')
使用這個方法可以通過id
、class
以及標籤元素,甚至是元素的一些屬性可以選擇一個元素。
id
選擇元素,需要在id
前使用#
class
選擇元素,需要在class
前使用.
甚至為了更好的理解或者記憶,只要滿足CSS的選擇器,那麼都可以被運用於document.querySelector(selector)
中的selector
選擇器。
document.querySelectorAll(selector)
document.querySelectorAll(selector)
可以幫助你選擇多個元素。這個方法中的selector
和document.querySelector()
具有相同的語法。唯一不同的是,你可以通過用逗號,
分隔來選擇多個元素。
比如:
var matches = document.querySelectorAll("div.note, div.alert");
DOM中節點共有12種類型,每種類型分別表示文檔中不同的信息標記。每個節點都擁有各自的特點、數據和方法,也與其他節點存在某種關係。節點之間的關係構成了層次,而所有頁面標記則表現為一個以特定節點為根節點的樹形結構。用張圖來描述:
所有的節點都有這些屬性,都是可以用於訪問相關的node
節點:
Node.childNodes
: 訪問一個單元素下所有的直接子節點元素,可以是一個可循環的類數組對象。該節點集合可以保護不同的類型的子節點(比如text節點或其他元素節點)。Node.firstChild
: 與childNodes
數組的第一個項(Element.childNodes[0]
)是同樣的效果,僅僅是快捷方式。Node.lastChild
: 與childNodes
數組的最後一個項(Element.childNodes[Element.childNodes.length-1]
)是同樣的效果,僅僅是快捷方式。Node.parentNode
: 訪問當前節點的父節點,父節點只能有一個,祖節點可以用Node.parentNode.parentNode
的形式來訪問。Node.nextSibling
: 訪問DOM樹上與當前節點同級別的下一個節點。Node.previousSibling
: 訪問DOM樹上與當前節點同級別的上一個節點。用張圖來闡述,會更清晰:
通過這張圖,理解起來就簡單多了,但有個非常重要的知識點:那就是元素之間不能有空格,如果ul
和li
之間有空格的話,就會被認為是內容為空的text node
節點,這樣ul.childNodes[0]
就不是第一個li
元素了。相應地,<p>
的下一個節點也不是<ul>
,因為<p>
和<ul>
之間有一個空行的節點,一般遇到這種情況需要遍歷所有的子節點然後判斷nodeType
類型。
根據上面的描述,我們可以把DOM中的節點相互之間存在著的各種關係分為:父子關係,兄弟關係等:
parentNode
:每個節點都有一個parentNode
屬性,它表示元素的父節點。Element
的父節點可能是Element
,Document
或DocumentFragment
;如果不存在,則返回null
parentElement
:返回元素的父元素節點,與parentNode
的區別在於,其父節點必須是一個Element
元素,如果不是,則返回null
;children
:返回一個實時的HTMLCollection
,子節點都是Element
;保存的是該節點的第一層元素子節點childNodes
:返回一個實時的NodeList
,表示元素的子節點列表,注意子節點可能包含文本節點、註釋節點等;firstChild
:返回第一個子節點,不存在返回null
,與之相對應的還有一個firstElementChild
;lastChild
:返回最後一個子節點,不存在返回null
,與之相對應的還有一個lastElementChild
;previousSibling
:節點的前一個節點,如果不存在則返回null
。注意有可能拿到的節點是文本節點或註釋節點,與預期的不符,要進行處理一下。nextSibling
:節點的後一個節點,如果不存在則返回null
。注意有可能拿到的節點是文本節點,與預期的不符,要進行處理一下。previousElementSibling
:返回前一個元素節點,前一個節點必須是Element
。nextElementSibling
:返回後一個元素節點,後一個節點必須是Element
。DOM操作在JavaScript還是很重要的,簡單點說,所有的交互操作都是基於DOM來操作的。而DOM中的操作,最為熟悉的就是對DOM的增、刪、改、查。今天的內容也就圍繞著這幾個方面展開。因為涉及到的內容較多,可能會有遺漏或者說零亂。如果你覺得上面不對之處,還請路過大神指正。
联系客服