由于 HTML 文檔被瀏覽器解析后就是一棵 DOM 樹简肴,要改變 HTML 的結(jié)構(gòu)吐限,就需要通過 JavaScript 來操作 DOM稠项。
操作一個(gè) DOM 節(jié)點(diǎn)實(shí)際上就是這么幾個(gè)操作:
- 更新:更新該 DOM 節(jié)點(diǎn)的內(nèi)容驾荣,相當(dāng)于更新了該 DOM 節(jié)點(diǎn)表示的HTML 的內(nèi)容;
- 遍歷:遍歷該 DOM 節(jié)點(diǎn)下的子節(jié)點(diǎn)帆吻,以便進(jìn)行進(jìn)一步操作域那;
- 添加:在該 DOM 節(jié)點(diǎn)下新增一個(gè)子節(jié)點(diǎn),相當(dāng)于動態(tài)增加了一個(gè) HTML 節(jié)點(diǎn)猜煮;
- 刪除:將該節(jié)點(diǎn)從 HTML 中刪除次员,相當(dāng)于刪掉了該 DOM 節(jié)點(diǎn)的內(nèi)容以及它包含的所有子節(jié)點(diǎn)。
獲取節(jié)點(diǎn)元素
在操作一個(gè) DOM 節(jié)點(diǎn)前王带,我們需要通過各種方式先拿到這個(gè) DOM 節(jié)點(diǎn)淑蔚。
最常用的方法是:
- document.getElementById()
- document.getElementsByTagName()
- 以及 CSS 選擇器 document.getElementsByClassName()
由于ID
在 HTML 文檔中是唯一的,所以document.getElementById()
可以直接定位唯一的一個(gè)DOM
節(jié)點(diǎn);
document.getElementsByTagName()
和document.getElementsByClassName()
總是返回一組 DOM 節(jié)點(diǎn)愕撰。要精確地選擇 DOM刹衫,可以先定位父節(jié)點(diǎn),再從父節(jié)點(diǎn)開始選擇搞挣,以縮小范圍带迟。
// 返回ID為'test'的節(jié)點(diǎn):
var test = document.getElementById('test');
// 先定位ID為'test-table'的節(jié)點(diǎn),再返回其內(nèi)部所有tr節(jié)點(diǎn):
var trs = document.getElementById('test-table').getElementsByTagName('tr');
// 先定位ID為'test-div'的節(jié)點(diǎn)囱桨,再返回其內(nèi)部所有class包含red的節(jié)點(diǎn):
var reds = document.getElementById('test-div').getElementsByClassName('red');
// 獲取節(jié)點(diǎn)test下的所有直屬子節(jié)點(diǎn):
var cs = test.children;
// 獲取節(jié)點(diǎn)test下第一個(gè)仓犬、最后一個(gè)子節(jié)點(diǎn):
var first = test.firstElementChild;
var last = test.lastElementChild;
第二種方法是使用querySelector()
和querySelectorAll()
,需要了解selector
語法舍肠,然后使用條件來獲取節(jié)點(diǎn)搀继,更加方便:
// 通過 querySelector 獲取 ID 為 q1 的節(jié)點(diǎn):
var q1 = document.querySelector('#q1');
// 通過 querySelectorAll 獲取 q1 節(jié)點(diǎn)內(nèi)的符合條件的所有節(jié)點(diǎn):
var ps = q1.querySelectorAll('div.highlighted > p');
更新 DOM
拿到一個(gè) DOM 節(jié)點(diǎn)后,我們可以對它進(jìn)行更新,直接修改節(jié)點(diǎn)的文本
方式一:修改innerHTML屬性翠语,這個(gè)方式非常強(qiáng)大叽躯,不但可以修改一個(gè)DOM節(jié)點(diǎn)的文本內(nèi)容,還可以直接通過HTML片段修改DOM節(jié)點(diǎn)內(nèi)部的子樹
// 獲取<p id="p_id">...</p>
var p = document.getElementById('p_id');
// 設(shè)置文本為ABC:
p.innerHTML = 'ABC'; // <p id="p-id">ABC</p>
// 設(shè)置HTML:
p.innerHTML = 'ABC <span style="color:red">RED</span> XYZ';
// <p>...</p>的內(nèi)部結(jié)構(gòu)已修改
方式二: 修改innerText
或textContent
屬性肌括,這樣可以自動對字符串進(jìn)行 HTML 編碼险毁,保證無法設(shè)置任何HTML標(biāo)簽
innerText
或textContent
的區(qū)別在于讀取屬性時(shí),innerText
不返回隱藏元素的文本,而textContent
返回所有文本
// 獲取<p id="p_id">...</p>
var p = document.getElementById('p_id');
// 設(shè)置文本:
p.innerText = '<script>alert("Hi")</script>';
// HTML被自動編碼畔况,無法設(shè)置一個(gè)<script>節(jié)點(diǎn):
// <p id="p-id"><script>alert("Hi")</script></p>
插入 DOM
獲得某個(gè) DOM 節(jié)點(diǎn),然后在這個(gè) DOM 節(jié)點(diǎn)內(nèi)插入新的 DOM
方式一:使用appendChild慧库,把一個(gè)子節(jié)點(diǎn)添加到父節(jié)點(diǎn)的最后一個(gè)子節(jié)點(diǎn)
例如:
<!-- HTML結(jié)構(gòu) -->
<p id="js">JavaScript</p>
<div id="list">
<p id="java">Java</p>
<p id="python">Python</p>
<p id="scheme">Scheme</p>
</div>
將 id
為 js
的標(biāo)簽插入到 <div>...</div> 便簽最后一項(xiàng)
var js = document.getElementById('js');
var list = document.getElementById('list');
list.appendChild(js);
結(jié)果:
<!-- HTML結(jié)構(gòu) -->
<div id="list">
<p id="java">Java</p>
<p id="python">Python</p>
<p id="scheme">Scheme</p>
<p id="js">JavaScript</p>
</div>
上面是把已知的元素插入到指定位置跷跪,但更多的時(shí)候我們會從零創(chuàng)建一個(gè)新的節(jié)點(diǎn),然后插入到指定位置:
var list = document.getElementById('list');
var swift = document.createElement('p');
swift.id = 'swift';
swift.innerText = 'Swift';
list.appendChild(swift);
結(jié)果:
<!-- HTML結(jié)構(gòu) -->
<div id="list">
<p id="java">Java</p>
<p id="python">Python</p>
<p id="scheme">Scheme</p>
<p id="swift">Swift</p>
</div>
方式二: 使用 insertBefore 把子節(jié)點(diǎn)插入到指定的位置
使用parentElement.insertBefore(newElement, referenceElement);
齐板,子節(jié)點(diǎn)會插入到referenceElement
之前吵瞻。
還是以上面的 HTML 為例,假定我們要把Swift
插入到Python
之前:
<!-- HTML結(jié)構(gòu) -->
<div id="list">
<p id="java">Java</p>
<p id="python">Python</p>
<p id="scheme">Scheme</p>
</div>
var list = document.getElementById('list');
var ref = document.getElementById('python');
var swift = document.createElement('p');
swift.id = 'swift';
swift.innerText = 'Swift';
list.insertBefore(swift, ref);
<!-- HTML結(jié)構(gòu) -->
<div id="list">
<p id="java">Java</p>
<p id="swift">Swift</p>
<p id="python">Python</p>
<p id="scheme">Scheme</p>
</div>
刪除DOM
刪除一個(gè)節(jié)點(diǎn)甘磨,首先要獲得該節(jié)點(diǎn)本身以及它的父節(jié)點(diǎn)橡羞,然后,調(diào)用父節(jié)點(diǎn)的removeChild
把自己刪掉
// 拿到待刪除節(jié)點(diǎn):
var self = document.getElementById('to-be-removed');
// 拿到父節(jié)點(diǎn):
var parent = self.parentElement;
// 刪除:
var removed = parent.removeChild(self);
removed === self; // true
注意济舆,當(dāng)從子節(jié)點(diǎn)數(shù)組中刪除節(jié)點(diǎn)時(shí)卿泽,需要防止數(shù)組越界
<div id="parent">
<p>First</p>
<p>Second</p>
</div>
執(zhí)行刪除操作
var parent = document.getElementById('parent');
parent.removeChild(parent.children[0]);
parent.removeChild(parent.children[1]); // <-- 瀏覽器報(bào)錯(cuò)
報(bào)錯(cuò)原因:
當(dāng)<p>First</p>
節(jié)點(diǎn)被刪除后,parent.children
的節(jié)點(diǎn)數(shù)量已經(jīng)從2
變?yōu)榱?code>1滋觉,索引[1]
已經(jīng)不存在了签夭。