DOM對映的特殊情況

發表於2024-02-24

DOM對映是前端開發中非常基礎的一塊內容,但是你知道嗎,DOM對映是有特殊情況的。我們看個例子:
有這樣一個結構

<body>
    <div></div>
</body>
let list = document.querySelectorAll('div');
document.body.appendChild(document.createElement('div'));
console.log(list); // NodeList [div]

想一下,為啥會只有一個div,按照DOM對映的機制,難道不應該兩個嗎?
別急,我們改行程式碼,就會發現答案

// querySelectorAll => getElementsByTagName
let list = document.getElementsByTagName('div');
// 以下程式碼沒有變動
document.body.appendChild(document.createElement('div'));
console.log(list); // HTMLCollection(2) [div, div]

querySelectorAll換成getElementsByTagName之後,便會發現,現在的輸出就成了我們期望的輸出了。
透過這個例子我們發現querySelectorAll是DOM對映的一個特殊case。根據《JavaScript高階程式設計(第三版)》的11章11.1.2的描述我們得知:querySelectorAll返回的值實際上是帶有所有屬性和方法的NodeList,其底層實現則類似於一組元素的快照,而非不斷對文件進行搜尋的動態查詢。這樣實現可以避免使用NodeList物件通常會引起的大多數效能問題。

所以我們使用這個方法的時候,在資料繫結完成後需要重新獲取一次才可以。(需要注意的是,它與原先存在的元素也是對映的,也就是可以修改屬性。但是新增或者刪除元素不會自動反映到這個集合中)。

你可能發現了,querySelectorAll返回的是一個NodeList,getElementsByTagName返回的是HTMLCollection。
他們之間有何不同呢?這個先挖個坑,下次再講。

那DOM對映還有其他的特殊case嗎?沒有了,就這一個。
順便我們再複習一下DOM對映的內容。

什麼是DOM對映

一般的,我們從頁面獲取的元素(包括我們建立的已經插入頁面的元素)和頁面中的元素是有聯動關係的,只要修改一個,另一個也會跟著改變。我們把這種聯動關係稱之為DOM對映。
舉個例子就是

1.改變元素物件的屬性

這是我們最常用到的一種場景。我們修改或新增元素屬性的時候,一般會從頁面中獲取到元素物件,對其進行修改,然後就能夠自動改變頁面元素的屬性。

//=> 修改從頁面中獲取的元素樣式
div.style.color = 'red';
//=> 修改已經插入頁面的元素的屬性
var p = document.createElement('p');
box.appendChild(p);
p.dataset.index = 1;

iShot_2024-02-23_18.36.12.gif

2. 向頁面內新增元素

<body>
    <div id='box'></div>
</body>
let divList = document.getElementsByTagName('div');
document.querySelector('#box').appendChild(document.createElement('div'));
console.log(divList); // HTMLCollection(2) [div#box, div]

我們向div中插入一個div,插入前只有一個我們的集合divList中只有一個元素,插入後再次獲取,裡面自動就包含了我們新插入的元素。

參考文件

相關文章