分享

JavaScript學習筆記:DOM的操作

 ipilipala 2018-09-28

通過上一節的學習,對JavaScript中的DOM有了一定的認識。雖然對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添加10000li,先用拼接字符串的方式來實現:

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');

多次刷新,可以看到創建10000li時,渲染所需要的時間如下圖:

把上面的示例,換成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.appendChildnode.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之前。

如果第二個參數referenceNodenull,則插入位置你父節點的末尾:

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的刪

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 中,仍然還可以被添加回文檔中。但是如果不使用一個變量保存這個節點的引用,被刪除的節點將不可達,會在某次垃圾回收被清除。

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的查

DOM節點中的查主要包括:查找元素(類似於CSS中的選擇器)和節點查找。

查找元素

先來看DOM中怎麼查找到元素,也就是說選擇到你想要的元素。在DOM中查找元素(選擇到想要的元素)對應的API主要有:

  • document.getElementById(id):匹配特定id的元素
  • document.getElementsByName(name):根據給定的name 返回一個在 (X)HTML documentNodeList集合
  • 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()方法,它將返回的是以當前元素為根節點,所有指定類名的子元素。

比如,獲取所有classitem的元素:

document.getElementsByClassName('item')

如果你想獲取多個class的元素時,可以用空格來隔開,比如說,同時獲取所有class同時包括btnbtn-lg的元素:

document.getElementsByClassName('btn btn-lg')

如果你想獲取某個元素的子節點中對應class的元素時,你也可以像下面這樣操作:

document.getElementById('box').getElementsByClassName('item')

document.querySelector(selector)

document.querySelector(selector)方法可以幫助你選擇一個HTML元素。如果選擇了多個HTML元素,其總是返回第一個元素。它看起來像這樣:

document.querySelector('li')

使用這個方法可以通過idclass以及標籤元素,甚至是元素的一些屬性可以選擇一個元素。

  • 使用一個id選擇元素,需要在id前使用#
  • 使用一個class選擇元素,需要在class前使用.
  • 使用一個標籤選擇元素,可以直接把元素標籤當作選擇器

甚至為了更好的理解或者記憶,只要滿足CSS的選擇器,那麼都可以被運用於document.querySelector(selector)中的selector選擇器。

document.querySelectorAll(selector)

document.querySelectorAll(selector)可以幫助你選擇多個元素。這個方法中的selectordocument.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樹上與當前節點同級別的上一個節點。

用張圖來闡述,會更清晰:

通過這張圖,理解起來就簡單多了,但有個非常重要的知識點:那就是元素之間不能有空格,如果ulli之間有空格的話,就會被認為是內容為空的text node節點,這樣ul.childNodes[0]就不是第一個li元素了。相應地,<p>的下一個節點也不是<ul>,因為<p><ul>之間有一個空行的節點,一般遇到這種情況需要遍歷所有的子節點然後判斷nodeType類型。

根據上面的描述,我們可以把DOM中的節點相互之間存在著的各種關係分為:父子關係,兄弟關係等:

父關係相關的API

  • parentNode:每個節點都有一個parentNode屬性,它表示元素的父節點。Element的父節點可能是ElementDocumentDocumentFragment;如果不存在,則返回null
  • parentElement:返回元素的父元素節點,與parentNode的區別在於,其父節點必須是一個Element元素,如果不是,則返回null

子關係API

  • children:返回一個實時的HTMLCollection,子節點都是Element;保存的是該節點的第一層元素子節點
  • childNodes:返回一個實時的NodeList,表示元素的子節點列表,注意子節點可能包含文本節點、註釋節點等;
  • firstChild:返回第一個子節點,不存在返回null,與之相對應的還有一個firstElementChild
  • lastChild:返回最後一個子節點,不存在返回null,與之相對應的還有一個lastElementChild

兄弟關係型API

  • previousSibling:節點的前一個節點,如果不存在則返回null。注意有可能拿到的節點是文本節點或註釋節點,與預期的不符,要進行處理一下。
  • nextSibling:節點的後一個節點,如果不存在則返回null。注意有可能拿到的節點是文本節點,與預期的不符,要進行處理一下。
  • previousElementSibling:返回前一個元素節點,前一個節點必須是Element
  • nextElementSibling:返回後一個元素節點,後一個節點必須是Element

總結

DOM操作在JavaScript還是很重要的,簡單點說,所有的交互操作都是基於DOM來操作的。而DOM中的操作,最為熟悉的就是對DOM的增、刪、改、查。今天的內容也就圍繞著這幾個方面展開。因為涉及到的內容較多,可能會有遺漏或者說零亂。如果你覺得上面不對之處,還請路過大神指正。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多