DOM 基本操作相關(guān)知識(shí)點(diǎn)整理

DOM

如今 Vue 和 React 框架應(yīng)該廣泛,封裝了 DOM。但 DOM 操作一直都是前端工程師的基礎(chǔ),必備知識(shí)。只會(huì) Vue 不懂 DOM 操作的前端程序員不會(huì)長久。

題目

  • DOM 屬于那種數(shù)據(jù)結(jié)構(gòu)?
  • DOM 操作常用的 API 有哪些?
  • attr 和 property 的區(qū)別?
  • 如果一次性插入多個(gè) DOM 節(jié)點(diǎn),考慮性能?

知識(shí)點(diǎn)

  • DOM 本質(zhì)
  • DOM 節(jié)點(diǎn)操作
  • DOM 結(jié)構(gòu)操作
  • DOM 性能

DOM 的本質(zhì)

DOM( Document Object Model ) 的本質(zhì)就是從 HTML 文件中解析構(gòu)件出來的樹。

DOM (Document Object Model) 譯為文檔對(duì)象模型,是 HTML 和 XML 文檔的編程接口。

HTML DOM 定義了訪問和操作 HTML 文檔的標(biāo)準(zhǔn)方法。

DOM 以樹結(jié)構(gòu)表達(dá) HTML 文檔。

DOM 節(jié)點(diǎn)操作

獲取 DOM 節(jié)點(diǎn)

// 通過 ID 獲取
const div1 = document.getElementById('div1')
console.log('div1', div1)

// 通過 Tag Name 獲取
const divList = document.getElementsByTagName('div') // 集合
console.log('divList.length', divList.length)
console.log('divList[1]', divList[1])

// 通過 Class Name 獲取
const containerList = document.getElementsByClassName('container') // 集合
console.log('containerList.length', containerList.length)
console.log('containerList[1]', containerList[1])

// 通過 CSS 選擇器來獲取
const pList = document.querySelectorAll('p')
console.log('pList', pList)
const p1 = pList[0]

節(jié)點(diǎn)中的 property

// 獲取節(jié)點(diǎn)
const pList = document.querySelectorAll('p')
const p = pList[0]

console.log(p.style.width)  // 獲取樣式
p.style.width = '100px' // 修改樣式
console.log(p.className)  // 獲取 class
p.className = 'p1'  // 修改 class

// 獲取 nodeName 和 nodeType
console.log(p.nodeName)
console.log(p.nodeType)

property 修改的是 js 變量(DOM節(jié)點(diǎn)對(duì)象)的屬性

節(jié)點(diǎn)中的 attribute

// 獲取節(jié)點(diǎn)
const pList = document.querySelectorAll('p')
const p = pList[0]
p.setAttribute('data-name', 'my-data')
console.log( p.getAttribute('data-name') )  // my-data

p.setAttribute('style', 'font-size:30px;')
console.log( p.getAttribute('style') )  // font-size:30px;

所謂的 attribute 是直接作用到標(biāo)簽上面的屬性

property 和 attribute 的區(qū)別

  • property:修改對(duì)象屬性,不會(huì)體現(xiàn)到 html 結(jié)構(gòu)中
  • attribute:修改 html 屬性,會(huì)改變 html 結(jié)構(gòu)
  • 然而兩者都可能引起 DOM 重新渲染(一般情況下盡量用 property 操作)

DOM 結(jié)構(gòu)操作

  • 新增插入節(jié)點(diǎn)
  • 獲取子元素,獲取父元素
  • 刪除子節(jié)點(diǎn)

下面 Demo 的 HTML 結(jié)構(gòu)

<body>
    <div id="div1" class="container">
        <p id="p1">一段文字 1</p>
        <p>一段文字 2</p>
        <p>一段文字 3</p>
    </div>
    <div id="div2">
        <img src="https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png"/>
    </div>
    <ul id="list">
    </ul>
</body>

新增插入節(jié)點(diǎn)

// 獲取 DOM 元素
const div1 = document.getElementById('div1')
const div2 = document.getElementById('div2')

// 新建節(jié)點(diǎn)
const newP = document.createElement('p')
newP.innerHTML = 'this is newP'

// 插入節(jié)點(diǎn)
div1.appendChild(newP)

// 移動(dòng)節(jié)點(diǎn)
const p1 = document.getElementById('p1')
div2.appendChild(p1)

獲取子元素,獲取父元素

// 獲取父元素
const div1 = document.getElementById('div1')
const parent = div1.parentNode

// 獲取子元素列表
const div1 = document.getElementById('div1')
const child = div1.childNodes

// 但是
console.log(child)  // NodeList(7) [ #text, p#p1, #text, p, #text, p, #text ]
// 打印結(jié)果顯示有 7 個(gè)元素,然而實(shí)際上 div1 下只有 3 個(gè) p 標(biāo)簽
// #text 的為文本元素

// text 元素 和 p 元素的 nodeType 不同
console.log(child[0].nodeType)  // #text 顯示為 3
console.log(child[1].nodeType)  // p 顯示為 1

// 把 nodeList 變成數(shù)組,然后通過 filter 函數(shù)過濾 p 標(biāo)簽
const div1ChildNodesP = Array.prototype.slice.call(div1.childNodes).filter(child => {
    if (child.nodeType === 1) {
        return true
    }
    return false
})
console.log('div1ChildNodesP', div1ChildNodesP) // [ p#p1, p, p ]

刪除子節(jié)點(diǎn)

const div1 = document.getElementById('div1')
const child = div1.childNodes
div1.removeChild( child[0] )

DOM 性能

  • DOM操作非常 “昂貴”(耗費(fèi)性能),應(yīng)避免頻繁的 DOM 操作
  • 可以對(duì) DOM 做緩存,從而減少 DOM 操作
  • 將頻繁操作改為一次性操作

DOM 查詢做緩存

// 不緩存 DOM 查詢結(jié)果
for (let i = 0; i < document.getElementsByTagName('p').length; i++) {
    // 每次循環(huán)都會(huì)重新計(jì)算 length , 頻繁進(jìn)行 DOM 查詢?。?!
}

// 緩存 DOM 查詢結(jié)果
const pList = document.getElementsByTagName('p')
const length = pList.length
for (let i = 0; i < length; i++) {
    // 緩存 length ,只進(jìn)行一次 DOM 查詢 :)
}

將頻繁操作改為一次性操作

const list = document.getElementById('list')

// 創(chuàng)建一個(gè)文檔片段,此時(shí)還沒有插入到 DOM 結(jié)構(gòu)中
const frag = document.createDocumentFragment()

for (let i  = 0; i < 20; i++) {
    const li = document.createElement('li')
    li.innerHTML = `List item ${i}`

    // 先插入文檔片段中
    frag.appendChild(li)
}

// 都完成之后,再統(tǒng)一插入到 DOM 結(jié)構(gòu)中
list.appendChild(frag)

總結(jié)

DOM 本質(zhì)就是從 HTML 文件中解析構(gòu)件出來的樹結(jié)構(gòu)。常用 API 有節(jié)點(diǎn)操作、結(jié)構(gòu)操作、attribute(修改 html 屬性) 和 property(修改對(duì)象屬性),一般盡量使用 property。性能方面應(yīng)該盡可能減少不必要的 DOM 操作,可以做查詢緩存或合并操作。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1.Label的作用是什么?是怎么用的 答案: label標(biāo)簽來定義表單控制間的關(guān)系當(dāng)用戶選擇該標(biāo)簽時(shí),瀏覽器會(huì)自...
    耶啵_閱讀 794評(píng)論 0 0
  • DOM 1. DOM節(jié)點(diǎn)獲取 2. DOM節(jié)點(diǎn)的property 修改的是JS變量的屬性,不會(huì)對(duì)標(biāo)簽產(chǎn)生什么樣的影...
    guoXuJianShu閱讀 1,460評(píng)論 0 0
  • 1.vue有哪些優(yōu)點(diǎn)? 答:輕量級(jí)框架:只關(guān)注視圖層,是一個(gè)構(gòu)建數(shù)據(jù)的視圖集合,大小只有幾十kb;簡單易學(xué):國人開...
    千鋒小書童閱讀 441評(píng)論 0 0
  • vue.jsjavascript 看看面試題,只是為了查漏補(bǔ)缺,看看自己那些方面還不懂。切記不要以為背了面試題,就...
    Leson17閱讀 2,964評(píng)論 0 13
  • 今天感恩節(jié)哎,感謝一直在我身邊的親朋好友。感恩相遇!感恩不離不棄。 中午開了第一次的黨會(huì),身份的轉(zhuǎn)變要...
    余生動(dòng)聽閱讀 10,852評(píng)論 0 11

友情鏈接更多精彩內(nèi)容