更新DOM
拿到一個DOM節(jié)點后磺送,我們可以對它進行更新。
可以直接修改節(jié)點的文本灿意,方法有兩種:
一種是修改innerHTML屬性,這個方式非常強大崇呵,不但可以修改一個DOM節(jié)點的文本內(nèi)容缤剧,還可以直接通過HTML片段修改DOM節(jié)點內(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)已修改
用innerHTML時要注意,是否需要寫入HTML域慷。如果寫入的字符串是通過網(wǎng)絡(luò)拿到了荒辕,要注意對字符編碼來避免XSS攻擊汗销。
第二種是修改innerText或textContent屬性,這樣可以自動對字符串進行HTML編碼抵窒,保證無法設(shè)置任何HTML標(biāo)簽:
// 獲取<p id="p-id">...</p>
var p = document.getElementBy('p-id');
// 設(shè)置文本:
p.innerText = '<script>alert("Hi")</script>';
// HTML被自動編碼,無法設(shè)置一個<script>節(jié)點:
// <p id="p-id"><script>alert("Hi")</script></p>
兩者的區(qū)別在于讀取屬性時弛针,innerText不返回隱藏元素的文本,而textContent返回所有文本李皇。另外注意IE<9不支持textContext削茁。
修改CSS也是經(jīng)常需要的操作。DOM節(jié)點的style屬性對應(yīng)所有的CSS掉房,可以直接獲取或設(shè)置茧跋。因為CSS允許font-size這樣的名稱,但它并非JavaScript有效的屬性名卓囚,所以需要在JavaScript中改寫為駝峰式命名 fontSize:
// 獲取<p id="p-id">...</p>
var p = document.getElementById('p-id');
// 設(shè)置CSS:
p.style.color = '#ff0000';
p.style.fontSize = '20px';
p.style.paddingTop = '2em';
<br />
插入DOM
當(dāng)我們獲得了某個DOM節(jié)點瘾杭,想在這個DOM節(jié)點內(nèi)插入新的DOM,應(yīng)該如何做?
如果這個DOM節(jié)點是空的哪亿,例如粥烁,<div></div>,那么蝇棉,直接使用innerHTML = '<span>child</span>'就可以修改DOM節(jié)點的內(nèi)容讨阻,相當(dāng)于“插入”了新的DOM節(jié)點。
如果這個DOM節(jié)點不是空的银萍,那就不能這么做变勇,因為innerHTML會直接替換掉原來的所有子節(jié)點。
有兩個辦法可以插入新的節(jié)點贴唇。一個是使用appendChild搀绣,把一個子節(jié)點添加到父節(jié)點的最后一個子節(jié)點。例如:
<!-- 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>
把<p id = "js">JavaScript</p>添加到<div id= "list">的最后一項:
var
js = document.getElementById('js'),
list = document.getElementById('list');
list.appendChild(js);
現(xiàn)在戳气,HTML結(jié)構(gòu)變成了這樣:
<!-- 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>
因為我們插入的js節(jié)點已經(jīng)存在于當(dāng)前的文檔樹链患,因此這個節(jié)點首先會從原先的位置刪除,再插入到新的位置瓶您。
更多的時候我們會從零創(chuàng)建一個新的節(jié)點麻捻,然后插入到指定位置:
var
list = document.getElementById('list'),
haskell = document.createElement('p');
haskell.id = 'haskell';
haskell.innerText = 'Haskell';
list.appendChild(haskell);
這樣我們就動態(tài)添加了一個新的節(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='haskell'>Haskell</p>
</div>
動態(tài)創(chuàng)建一個節(jié)點然后添加到DOM樹種,可以實現(xiàn)很多功能呀袱。舉個例子贸毕,下面的代碼動態(tài)創(chuàng)建了一個<style>節(jié)點,然后把它添加到<head>節(jié)點的末尾夜赵,這樣就動態(tài)地給文檔添加了新的CSS定義:
var d = document.createElement('style');
d.setAttribute('type', 'text/css');
d.innerHTML = 'p { color: red}';
document.getElementsByTagName('head')[0].appendChild(d);
可以在Chrome的控制臺執(zhí)行上述代碼明棍,觀察頁面樣式的變化。
<h2>insertBefore</h2>
如果我們要把子節(jié)點插入到指定的位置怎么辦寇僧?可以使用
parentElement.insertBefore(newElement, referenceElement); ,子節(jié)點會插入到referenceElement之前摊腋。
還是以上面的HTML為例沸版,假定我們要把Haskell插入到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'),
ref = document.getElementById('python'),
haskell = document.createElement('p');
haskell.id = 'haskell';
haskell.innerText = 'Haskell';
list.insertBefore(haskell, ref);
新的HTML結(jié)構(gòu)如下:
<!-- HTML結(jié)構(gòu) -->
<div id="list">
<p id="java">Java</p>
<p id="haskell">Haskell</p>
<p id="python">Python</p>
<p id="scheme">Scheme</p>
</div>
可見,使用insertBefore重點是要拿到一個“參考子節(jié)點”的引用兴蒸。很多時候视粮,需要循環(huán)一個父節(jié)點的所有子節(jié)點,可以通過迭代children屬性實現(xiàn):
var
i, c,
list = document.getElementById('list');
for (i = 0; i < list.children.length; i++) {
c = list.children[i]; // 拿到第i個子節(jié)點
}
刪除DOM
刪除一個DOM節(jié)點就比插入要容易得多橙凳。
要刪除一個節(jié)點蕾殴,首先要獲得該節(jié)點本身以及它的父節(jié)點,然后痕惋,調(diào)用父節(jié)點的removeChild把自己刪掉:
// 拿到待刪除節(jié)點:
var self = document.getElementById('to-be-removed');
// 拿到父節(jié)點:
var parent = self.parentElement;
// 刪除:
var removed = parent.removeChild(self);
removed ===self; // true
注意到刪除后的節(jié)點雖然不在文檔樹中了区宇,但其實它還在內(nèi)存中,可以隨時再次被添加到別的位置值戳。
當(dāng)你遍歷一個父節(jié)點的子節(jié)點并進行刪除操作時议谷,要注意,children屬性是一個只讀屬性堕虹,并且它在子節(jié)點變化時會實時更新卧晓。
例如,對于如下HTML結(jié)構(gòu):
<div id="parent">
<p>First</p>
<p>Second</p>
</div>
當(dāng)我們用如下代碼刪除子節(jié)點時:
var parent = document.getElementById('parent');
parent.removeChild(parent.children[0]);
parent.removeChild(parent.children[1]); // <---瀏覽器報錯
瀏覽器報錯:parent.children[1]不是一個有效的節(jié)點赴捞。原因就在于逼裆,當(dāng)<p>First</p>
節(jié)點被刪除后,parent.children的節(jié)點數(shù)量已經(jīng)從2變?yōu)榱?赦政,索引[1]已經(jīng)不存在了胜宇。
因此,刪除多個節(jié)點時恢着,要注意children屬性時刻都在變化桐愉。
練習(xí)(刪除節(jié)點)
<!-- HTML結(jié)構(gòu) -->
<ul id="test-list">
<li>JavaScript</li>
<li>Swift</li>
<li>HTML</li>
<li>ANSI C</li>
<li>CSS</li>
<li>DirectX</li>
</ul>
把與Web開發(fā)技術(shù)不相關(guān)的節(jié)點都刪掉:
// TODO
var list = document.getElementById('test-list').children;
for (var i = 0; i < list.length; !flag?i++:i){
var flag=false;
if (list[i].innerHTML !== 'JavaScript' && list[i].innerHTML !== 'HTML' && list[i].innerHTML !== 'CSS') {
list[i].parentElement.removeChild(list[i]);
flag=true;
}
}
// 測試:
;(function () {
var
arr, i,
t = document.getElementById('test-list');
if (t && t.children && t.children.length === 3) {
arr = [];
for (i = 0; i < t.children.length; i ++) {
arr.push(t.children[i].innerText);
}
if (arr.toString() === ['JavaScript', 'HTML', 'CSS'].toString()) {
alert('測試通過!');
}
else {
alert('測試失敗: ' + arr.toString());
}
}
else {
alert('測試失敗!');
}
})();