JavaScript的DOM操作

JavaScript的DOM操作

由于HTML文檔被瀏覽器解析后就是一顆DOM樹佑笋,就需要通過JavaScript來操作DOM备籽。

始終記住DOM是一個(gè)樹形結(jié)構(gòu)离熏。操作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)一步操作
  • 添加:在該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)

在操作一個(gè)DOM節(jié)點(diǎn)之前,我們需要通過各種方式先拿到這個(gè)DOM節(jié)點(diǎn)晌柬。最常用的方法是getElementById()getElementsByTagName()姥份,以及CSS選擇器getElementsByClassName()

由于ID在HTML文檔中是唯一的年碘,所有document澈歉。getElementByID()可以直接定位唯一的一個(gè)DOM節(jié)點(diǎn)getElementsByTagName()getElementsByClassName()總是返回一組DOM節(jié)點(diǎn)盛泡。要精確地選擇DOM闷祥,可以先定位父節(jié)點(diǎn),再從父節(jié)點(diǎn)開始選擇,以縮小范圍凯砍。

例如:

//返回id為test的節(jié)點(diǎn)
var test = document.getElementById('test');

//先定位id為table的節(jié)點(diǎn)箱硕,再返回內(nèi)部所有tr節(jié)點(diǎn)
var tests = document.getElementById('table').getElementsByTagName('tr');

//先定位ID為table的節(jié)點(diǎn),再返回其內(nèi)部所有class包含red的節(jié)點(diǎn)
var tests = document.getElementById('table').getElementsByClassName('red');

//獲取節(jié)點(diǎn)test下的所有直屬節(jié)點(diǎn)
var cs = test.child;

//獲取節(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');

低版本的IE < 8 不支持上面兩個(gè)操作座泳,IE8僅有限支持惠昔。

嚴(yán)格地講,我們這里的DOM節(jié)點(diǎn)是指Elment挑势,但是DOM節(jié)點(diǎn)實(shí)際上是Node镇防,在HTML中,Node包括Element潮饱、Comment来氧、CDATA_SECTION等很多種,以及根節(jié)點(diǎn)Document類型香拉,但是啦扬,絕大多數(shù)我們只關(guān)心Element,也就是實(shí)際控制頁面的Node凫碌,其他類型的Node忽略即可扑毡。根節(jié)點(diǎn)Document已經(jīng)自動綁定為全局變量document。

更新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)部的子樹。
//獲取id為p-id的元素
var p = document.getElementById('p-id');
//設(shè)置文本為ABC
p.innerHTML = 'ABC';
//設(shè)置HTML的屬性
p.innerHTML = 'ABC<span style ="color:red">RED</span>';

用innerHTML時(shí)要注意挺邀,是否需要寫入HTML揉忘。如果寫入的字符是通過網(wǎng)絡(luò)拿到的,要注意對字符進(jìn)行編碼來避免XSS攻擊

  • 第二種是修改innerText和textContent屬性端铛,這樣可以自動對字符串進(jìn)行HTML編碼泣矛,保證無法設(shè)置任何HTML標(biāo)簽。
var p = document.getElementById('p-id');
p.innerText = 'abc';

兩者的區(qū)別在于innerText不返回隱藏元素的文本禾蚕,而textContent返回所有文本您朽,注意IE < 9不支持textContent。

此外,修改CSS也是經(jīng)常需要的操作哗总。DOM節(jié)點(diǎn)的style屬性對應(yīng)所有的CSS几颜,可以直接獲取或設(shè)置。因?yàn)镃SS允許font-size這樣的名稱讯屈,但它并非JavaScript有效的屬性名蛋哭,所以需要在JavaScript中改為駝峰式命名fontSize。

var p = document.getElementById('p-id');
//設(shè)置CSS
p.style.color = '#ff0000';
p.style.fontSize = '20px';
p.style.paddingTop = '2em';

插入DOM

當(dāng)我們獲取了某個(gè)DOM節(jié)點(diǎn)之后涮母,如果想要在這個(gè)DOM節(jié)點(diǎn)內(nèi)插入新的DOM節(jié)點(diǎn)谆趾,應(yīng)該如何做?

如這個(gè)DOM是空的叛本,例如沪蓬,<div></div>,那么,直接使用innerHTML = <span>child</span>就可以修改DOM節(jié)點(diǎn)的內(nèi)容来候,相當(dāng)于插入例如新的DOM節(jié)點(diǎn)怜跑。
如果這個(gè)DOM節(jié)點(diǎn)不是空的,那就不能這么做吠勘,因?yàn)閕nnerHTML會直接替換掉原來的所有子節(jié)點(diǎn)性芬。這種情況下插入新節(jié)點(diǎn)有兩個(gè)方法:

  • 一是使用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>

<p id="js">JavaScript</p>添加到<div id="list">的最后一項(xiàng):

var
    js = document.getElementById('js');
    list = document.getElementById('lis');
list.appendChild(js);

現(xiàn)在植锉,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>

因?yàn)槲覀儾迦氲膉s節(jié)點(diǎn)已經(jīng)存在于當(dāng)前的DOM中,因此這個(gè)節(jié)點(diǎn)首先會從原先的位置刪除峭拘,再插入到新的位置俊庇。

下面,我們來看看從零創(chuàng)建一個(gè)新的節(jié)點(diǎn)鸡挠,然后插入到指定的位置:

var
    list = document.getElementById('lis');
    haskell = document.createElement('p');
haskell.id = 'haskell';
haskell.innerText = 'Haskell';
list.appendChild(haskell)

這樣我們就動態(tài)添加了一個(gè)新的節(jié)點(diǎn):

<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)建一個(gè)節(jié)點(diǎn)然后添加到DOM樹中辉饱,可以實(shí)現(xiàn)很多功能。舉個(gè)例子拣展,下面的代碼創(chuàng)建一個(gè)<style>節(jié)點(diǎn)彭沼,然后把它添加到<head>節(jié)點(diǎn)的末尾,這樣就動態(tài)地給文檔添加了新的CSS定義:

var d = document.createElement('style');
d.setAttribute('type','text/css');
d.innerHTML = 'p{color:red}';
document.getElementsByTagName('head')[0].appendChild(d);
  • 二是使用insertBefore备埃,把子節(jié)點(diǎn)插入到指定的位置姓惑。使用parentElement.insertBefore(newElement,referenceElement),子節(jié)點(diǎn)會插入到referenceElement之前。

還是以上面HTML為例按脚,假設(shè)我們要把Haskell插入到Python之前:

<div id="list">
    <p id = "java">Java</p>
    <p id = "python">python</p>
    <p id = "scheme">Scheme</p>
</div>

可以這么寫:

var
    list = document.getElementById('lis');
    ref = document.getElementById('python');
    haskell = document.createElement('p');
haskell.id = 'haskell';
haskell.innerText = 'Haskell';
list.insertBefore(haskell,ref);

新的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重點(diǎn)是要拿到一個(gè)參考子節(jié)點(diǎn)的引用。很多時(shí)候辅搬,需要一個(gè)父節(jié)點(diǎn)的所有子節(jié)點(diǎn)唯沮,可以通過迭代children屬性來實(shí)現(xiàn)。

var
    i,c,
    list = document.getElementById('list');
    for(i = 0; i < list.children.length; i++) {
        c = list.children[i]; //拿到第i個(gè)子節(jié)點(diǎn)
    }

刪除DOM

刪除一個(gè)DOM節(jié)點(diǎn)就比插入要容易得多。要刪除一個(gè)節(jié)點(diǎn)介蛉,首先要獲得該節(jié)點(diǎn)本身以及它的父節(jié)點(diǎn)夯缺,然后,調(diào)用父節(jié)點(diǎn)的removeChild把自己刪掉:

//拿到帶刪除節(jié)點(diǎn)
var self = document.getElementById('removed');
//拿到父節(jié)點(diǎn)
var parent = self.parentElement;
//刪除
var removed = parent.removeChild(self);
removed == self; //true

注意到刪除的DOM節(jié)點(diǎn)雖然不在文檔樹了甘耿,但其實(shí)它還在內(nèi)存中踊兜,可以隨時(shí)再次被添加到別的位置。
當(dāng)你遍歷一個(gè)父節(jié)點(diǎn)的子節(jié)點(diǎn)并進(jìn)行刪除操作時(shí)佳恬,要注意捏境,children屬性只是一個(gè)只讀屬性,并且它在子節(jié)點(diǎn)變化時(shí)會實(shí)時(shí)更新毁葱。

例如垫言,對如下的HTML結(jié)構(gòu):

<div id="parent" >
    <p>First</P>
    <p>Second</P>
</div>

當(dāng)我們用如下代碼刪除子節(jié)點(diǎn)時(shí):

var parent = document.getElementById('parent');
parent.removeChild(parent.children[0]);
parent.removeChild(parent.children[1]); //瀏覽器報(bào)錯

瀏覽器報(bào)錯:parent.children[1]不是一個(gè)有效節(jié)點(diǎn)。原因就在于倾剿,當(dāng)<p>First</P>節(jié)點(diǎn)被刪除后筷频,parent.children的節(jié)點(diǎn)數(shù)量已經(jīng)從2變?yōu)?,索引[1]已經(jīng)不存在了前痘。因此凛捏,當(dāng)刪除多個(gè)節(jié)點(diǎn)的時(shí),要注意children屬性時(shí)刻都在變化芹缔。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末坯癣,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子最欠,更是在濱河造成了極大的恐慌示罗,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,376評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件芝硬,死亡現(xiàn)場離奇詭異蚜点,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)拌阴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評論 2 385
  • 文/潘曉璐 我一進(jìn)店門绍绘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人皮官,你說我怎么就攤上這事脯倒∈导” “怎么了捺氢?”我有些...
    開封第一講書人閱讀 156,966評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長剪撬。 經(jīng)常有香客問我摄乒,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,432評論 1 283
  • 正文 為了忘掉前任馍佑,我火速辦了婚禮斋否,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘拭荤。我一直安慰自己茵臭,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,519評論 6 385
  • 文/花漫 我一把揭開白布舅世。 她就那樣靜靜地躺著旦委,像睡著了一般。 火紅的嫁衣襯著肌膚如雪雏亚。 梳的紋絲不亂的頭發(fā)上缨硝,一...
    開封第一講書人閱讀 49,792評論 1 290
  • 那天,我揣著相機(jī)與錄音罢低,去河邊找鬼查辩。 笑死,一個(gè)胖子當(dāng)著我的面吹牛网持,可吹牛的內(nèi)容都是我干的宜岛。 我是一名探鬼主播,決...
    沈念sama閱讀 38,933評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼功舀,長吁一口氣:“原來是場噩夢啊……” “哼谬返!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起日杈,我...
    開封第一講書人閱讀 37,701評論 0 266
  • 序言:老撾萬榮一對情侶失蹤遣铝,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后莉擒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體酿炸,經(jīng)...
    沈念sama閱讀 44,143評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,488評論 2 327
  • 正文 我和宋清朗相戀三年涨冀,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了填硕。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,626評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡鹿鳖,死狀恐怖扁眯,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情翅帜,我是刑警寧澤姻檀,帶...
    沈念sama閱讀 34,292評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站涝滴,受9級特大地震影響绣版,放射性物質(zhì)發(fā)生泄漏胶台。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,896評論 3 313
  • 文/蒙蒙 一杂抽、第九天 我趴在偏房一處隱蔽的房頂上張望诈唬。 院中可真熱鬧,春花似錦缩麸、人聲如沸铸磅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽愚屁。三九已至,卻和暖如春痕檬,著一層夾襖步出監(jiān)牢的瞬間霎槐,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工梦谜, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留丘跌,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓唁桩,卻偏偏與公主長得像闭树,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子荒澡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,494評論 2 348

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