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

DOM

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

題目

  • 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)件出來(lái)的樹(shù)。

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

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

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

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

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

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

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

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

// 通過(guò) CSS 選擇器來(lái)獲取
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ù)組告唆,然后通過(guò) filter 函數(shù)過(guò)濾 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 查詢DK!茄螃!
}

// 緩存 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í)還沒(méi)有插入到 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)件出來(lái)的樹(shù)結(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)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市盯孙,隨后出現(xiàn)的幾起案子鲁森,更是在濱河造成了極大的恐慌,老刑警劉巖振惰,帶你破解...
    沈念sama閱讀 217,657評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件歌溉,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡骑晶,警方通過(guò)查閱死者的電腦和手機(jī)痛垛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)桶蛔,“玉大人匙头,你說(shuō)我怎么就攤上這事∽欣祝” “怎么了蹂析?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,057評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)碟婆。 經(jīng)常有香客問(wèn)我电抚,道長(zhǎng),這世上最難降的妖魔是什么脑融? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,509評(píng)論 1 293
  • 正文 為了忘掉前任喻频,我火速辦了婚禮,結(jié)果婚禮上肘迎,老公的妹妹穿的比我還像新娘甥温。我一直安慰自己,他們只是感情好妓布,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布姻蚓。 她就那樣靜靜地躺著,像睡著了一般匣沼。 火紅的嫁衣襯著肌膚如雪狰挡。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,443評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音加叁,去河邊找鬼倦沧。 笑死,一個(gè)胖子當(dāng)著我的面吹牛它匕,可吹牛的內(nèi)容都是我干的展融。 我是一名探鬼主播,決...
    沈念sama閱讀 40,251評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼豫柬,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼告希!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起烧给,我...
    開(kāi)封第一講書(shū)人閱讀 39,129評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤燕偶,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后础嫡,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體指么,經(jīng)...
    沈念sama閱讀 45,561評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評(píng)論 3 335
  • 正文 我和宋清朗相戀三年驰吓,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了涧尿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,902評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡檬贰,死狀恐怖姑廉,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情翁涤,我是刑警寧澤桥言,帶...
    沈念sama閱讀 35,621評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站葵礼,受9級(jí)特大地震影響号阿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜鸳粉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評(píng)論 3 328
  • 文/蒙蒙 一扔涧、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧届谈,春花似錦枯夜、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,838評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至曙搬,卻和暖如春摔吏,著一層夾襖步出監(jiān)牢的瞬間鸽嫂,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,971評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工征讲, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留据某,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,025評(píng)論 2 370
  • 正文 我出身青樓稳诚,卻偏偏與公主長(zhǎng)得像哗脖,于是被迫代替她去往敵國(guó)和親瀑踢。 傳聞我的和親對(duì)象是個(gè)殘疾皇子扳还,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評(píng)論 2 354

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

  • 1.Label的作用是什么?是怎么用的 答案: label標(biāo)簽來(lái)定義表單控制間的關(guān)系當(dāng)用戶選擇該標(biāo)簽時(shí),瀏覽器會(huì)自...
    耶啵_閱讀 727評(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,316評(píng)論 0 0
  • 1.vue有哪些優(yōu)點(diǎn)氨距? 答:輕量級(jí)框架:只關(guān)注視圖層,是一個(gè)構(gòu)建數(shù)據(jù)的視圖集合棘劣,大小只有幾十kb俏让;簡(jiǎn)單易學(xué):國(guó)人開(kāi)...
    千鋒小書(shū)童閱讀 330評(píng)論 0 0
  • vue.jsjavascript 看看面試題,只是為了查漏補(bǔ)缺茬暇,看看自己那些方面還不懂首昔。切記不要以為背了面試題,就...
    Leson17閱讀 2,809評(píng)論 0 13
  • 今天感恩節(jié)哎糙俗,感謝一直在我身邊的親朋好友勒奇。感恩相遇!感恩不離不棄巧骚。 中午開(kāi)了第一次的黨會(huì)赊颠,身份的轉(zhuǎn)變要...
    迷月閃星情閱讀 10,564評(píng)論 0 11