DOM節點增刪查改替換複製
這篇文章中總結的節點操作比較狹義,特指對 element 節點的操作,並沒有包含其他內容,至於對文本內容和屬性的操作就放在下一篇吧~
節點的“查”操作已經在上一篇文章中總結過了,在本文中主要包括創建節點、修改節點、插入節點、刪除節點、替換節點、查看節點和複製節點
今天的通過下面這一段範例代碼展開:
<ul id="users">
<li class="user">小A君</li>
<li class="user">小C君</li>
</ul>
我們可以設想這樣一個應用場景,根據上面的結構,創建兩個新的“小B君”和“小D君”,按照 ABCD 的順序插入到上面的列表中
那麼我們就開始吧~
創建節點
createElement
創建 element 節點主要依賴 createElement
方法,這個方法接受一個參數,即要創建的標籤名:
let tempLi = document.createElement('li');
console.log(tempLi); // <li></li>
這個標籤名並不區分大小寫,但是按照標準最好還是採用小寫~
當 element 被創建的時候,它所屬的 document 就被設置好了,
修改節點
當一個空的 element 創建出來後,就要根據我們的需求爲其添加內容
如果我們要添加的是文本內容,可以採用下面的幾個方法;
- innerText
- textContent
而關於添加(插入)節點的內容就放在下一節 插入節點 中
innerText
innerText 屬性是一個可讀可寫的屬性,它可以操作元素中包含的所有文本內容,包括子文檔樹中的文本。在通過innerText讀取值時,它會按照由淺入深地順序,將子文檔樹中的所有文本拼接起來。在通過innerText寫入值時,結果會刪除元素的所有子節點,插入包含相應文本值的文本節點
console.log(document.getElementById('users').innerText); // 小A君 小B君
而當我們進行寫操作的時候,會直接將這個 element 中的所有子節點清除並添加一個文本節點(可以採用 element.innerText = ''
來清空一個元素),猜一下當我們執行下面這段代碼的時候會發生什麼:
let usersEle = document.getElementById('users');
usersEle.innerText = usersEle.innerText;
(如果真的寫了這樣的代碼會被人打死的吧,咳咳~)
textContent
這個屬性和 innerText 的使用方法基本一致,textContent 屬性與 innerText 屬性類似,該屬性可讀寫。在讀模式下,返回當前節點和它的所有後代節點的文本內容;在寫模式下,結果會刪除元素的所有子節點,插入包含相應文本值的文本節點
他們的主要區別在於 innerText 是 element 的屬性,而 textContent 是 node 的屬性且 textContent 不兼容 IE9 以下瀏覽器
console.log(document.getElementById('users').textContent); // 小A君 小B君
插入節點
在創建好節點並添加好內容之後我們應該將節點插入到他們的父節點中了,插入節點的方法也不止一種
- appendChild
- insertBefore
appendChild
這個方法的作用可以很明顯通過方法名理解,就是直接將一個 child 節點 append 進來,在節點的最後追加一個子節點
使用方法:
let tempLi = document.createElement('li');
tempLi.innerText = "小D君";
document.getElementById('users').appendChild(tempLi);
由於這個方法只能將節點添加到父節點的最後,所以在使用時需要注意順序方面的要求,通常的做法是先進行一定的排序後再調用這個方法
⚠️注意: 如果要添加的節點已經存在在這個 document 中了,並不是新創建出來的 element,這時會發生的並不是單純的插入,而是“移動”
<!-- html body -->
<ul id="users">
<li class="user">小A君</li>
<li class="user">小C君</li>
</ul>
<script>
document.getElementById('users').appendChild(
document.getElementsByClassName('user')[0]
)
</script>
insertBefore
insertBefore() 方法接收兩個參數:要插入的節點和作爲參照的節點。插入節點後,被插入的節點會變成參照節點的前一個兄弟節點(previousSibling),同時被方法返回。如果參照節點是null,則insertBefore()與appendChild()方法執行相同的操作
同樣地,如果插入的節點已經是文檔的一部分了,那結果就是將該節點從原來的位置轉移到新位置
這個方法就更加適合 “小B君” 的插入
let tempLi = document.createElement('li');
tempLi.innerText = "小B君";
document.getElementById('users').insertBefore(
tempLi,
document.getElementsByClassName('user')[1]
);
刪除節點
removeChild
removeChild 方法接收一個參數,即要移除的節點,被移除的節點成爲方法的返回值
let user0 = document.getElementsByClassName('user')[0];
document.getElementById('users').removeChild(user0);
remove()
remove 方法不太常見,直接在當前節點使用 remove() 方法就可以刪除該節點,無返回值
要實現和上面一樣的效果只需要
document.getElementsByClassName('user')[0].remove();
替換節點
replaceChild
replaceChild 接收的兩個參數是要插入的節點和要替換的節點,要替換的節點將由這個方法返回並從文檔樹中移除,同時由要插入的節點佔據其位置
let tempLi = document.createElement('li');
tempLi.innerText = "替換節點";
document.getElementById('users').replaceChild(
tempLi,
document.getElementsByClassName('user')[0]
);
複製節點
cloneNode
cloneNode 方法用於克隆一個節點
調用者是要被複制的 node,返回值是這個 node 的副本
它接受一個布爾值作爲參數,表示是否執行深複製。在參數爲true時,執行深複製,也就是複製節點及整個子節點樹。在參數爲false的情況下,執行淺複製,即複製節點本身
let dupUsers = document.getElementById('users').cloneNode(true);
console.log(dupUsers);
⚠️注意: 由於不同版本規範中 cloneNode 方法的默認參數不同,所以請一定加上參數
終極大招 innerHTML
上述提到的所有問題,都可以通過 innerHTML 解決
這個方法和前文中提到的 innerText 很相似
- 在讀模式下,返回與調用元素的所有子節點(包括元素、註釋和文本節點)對應的HTML字符串;
- 在寫模式下,innerHTML會根據指定的值創建新的DOM樹,然後用這個DOM樹完全替換調用元素原先的所有子節點
我們可以在讀模式下獲取到我們要操作的 node 或者他的 父節點,之後通過字符串處理方法進行操作,然後再寫入
但是我們一般不會這樣做
主要是因爲它存在安全問題,innerHTML不會檢查代碼,直接運行,會有風險
所以innerHTML方法建議僅用於新的節點,比如創建插入,內容最好是可控的,而不是用戶填寫的內容