深入學習DOM模型基礎
本文和大家重點討論一下DOM模型的概念和用法,DOM的全稱是DocumentObjetModule即文檔對象模型,在Web上把頁面的HTML表現(xiàn)看作一個有樹型結(jié)構(gòu)的對象模型,可以通過一些操作接口來對Document的每一個子對象節(jié)點進行訪問和操作,這就為Ajax在不刷新頁面的情況下改變頁面顯示數(shù)據(jù)成為了可能。
DOM模型基礎
DOM的全稱是DocumentObjetModule即文檔對象模型,在Web上把頁面的HTML表現(xiàn)看作一個有樹型結(jié)構(gòu)的對象模型,可以通過一些操作接口來對Document的每一個子對象節(jié)點進行訪問和操作,這就為Ajax在不刷新頁面的情況下改變頁面顯示數(shù)據(jù)成為了可能。
先來看一個簡單的HTML片段:
- <htmlxmlnshtmlxmlns="http://www.w3.org/1999/xhtml">
 - <head><title>DOM模型</title></head><body>
 - <labeltitlelabeltitle="title1">DOM模型節(jié)點</label></body></html>
 
在這個HTML頁面中,只有一個Label控件,可以根據(jù)節(jié)點的層次畫出這個頁面的層次結(jié)構(gòu)圖。
通常來說,在HTML文檔中的每一個標簽都表示一個對象節(jié)點。而像上面<Lable>這樣的標簽是我們的HTML元素節(jié)點,而標簽中的title=“title1”是一個屬性節(jié)點,而“DOM模型節(jié)點”這樣的文本構(gòu)成了一個文本節(jié)點。
那么,怎么才能對DOM模型中的一個節(jié)點進行操作呢,首先要做的是對這個節(jié)點進行引用。
1.對文檔節(jié)點的引用
下面列舉一些常用的對文檔元素節(jié)點的引用方法。
◆document.GetElementById()方法直接引用節(jié)點,這個是我們在實際應用中最常用的一種方法,在HTML文檔中每一個元素節(jié)點都可以定義一個唯一的id屬性,然后使用GetElementById方法就可以準確地得到對這個節(jié)點的引用。
- <htmlxmlnshtmlxmlns="http://www.w3.org/1999/xhtml">
 - <head><title>DOM模型</title></head><body><dividdivid="Div1">
 - <labeltitlelabeltitle="title1">Dom模型節(jié)點</label></div></body>
 - </html><scriptlanguagescriptlanguage="javascript"type="text/javascript">
 - <!--var_div1=document.getElementById("Div1");
 - alert(_div1.innerHTML);//彈出警告框顯示了標簽div中的HTML內(nèi)容
 - //<labeltitlelabeltitle="title1">Dom模型節(jié)點</label>--></script>
 
HTML文檔中每一個元素節(jié)點都有innerHTML這個屬性,我們通過對這個屬性的訪問可以獲取或者設置這個元素節(jié)點標簽內(nèi)的HTML內(nèi)容,自IE4.0以來越來越多的瀏覽器支持了這一屬性,通過使用這一屬性使許多繁雜的動態(tài)生成HTML的工作變得簡單。需要注意的是,我們?nèi)绻麑螛擞洏撕?,?lt;img>這一類標簽的innerHTML屬性讀取會得到一個空字符串,而寫將會得到一個錯誤。
此外document對象還有一個類似的方法GetElementByName,我們可以通過form標簽的name屬性對表單元素節(jié)點進行引用,但返回的通常是一個數(shù)組,因為表單中的節(jié)點name屬性的值不是唯一的,可以通過索引器得到每一個元素的引用。
◆document.getElementByTagName()
可以得到一個指定標記名稱節(jié)點引用的數(shù)組集合,可以通過索引器對每個節(jié)點的引用進行訪問。
- <htmlxmlnshtmlxmlns="http://www.w3.org/1999/xhtml"><head>
 - <title>DOM模型</title></head><body>
 - <dividdivid="Div1">節(jié)點1</div><dividdivid="Div2">節(jié)點2</div>
 - </body></html><scriptlanguagescriptlanguage="javascript"
 - type="text/javascript">
 - <!--var_divs=document.getElementsByTagName("div");
 - for(vari=0;i<_divs.length;i++)alert(_divs[i].innerHTML);
 - //依次顯示了"節(jié)點1"和"節(jié)點2"--></script>
 
這個方法通常在要對整個文檔的某一類元素節(jié)點進行操作時用到,比如說為全部的圖片添加一個鼠標掠過時發(fā)生位移的效果,這時就可以通過這個方法對文檔所有的節(jié)點進行引用。
◆parentNode和childNodes,可以通過訪問這兩個屬性獲得當前節(jié)點的父節(jié)點和子節(jié)點集合的引用。
- <htmlxmlnshtmlxmlns="http://www.w3.org/1999/xhtml">
 - <head><title>DOM模型</title></head>
 - <body><dividdivid="Div1"><spanidspanid="sp1">節(jié)點1</span>
 - <spanidspanid="sp2">節(jié)點2</span></div></body></html>
 - <scriptlanguagescriptlanguage="javascript"type="text/javascript">
 - <!--var_nod=document.getElementById("sp1");
 - //得到對sp1的引用var_pNod=_nod.parentNode;
 - //得到對Div1的引用alert(_pNod.innerHTML);
 - //顯示父節(jié)點內(nèi)容for(vari=0;i<_pNod.childNodes.length;i++)
 - //循環(huán)子節(jié)點alert(_pNod.childNodes[i].innerHTML);
 - //依次顯示了每一個節(jié)點的內(nèi)容--></script>
 
在這里問題出現(xiàn)了,我們發(fā)現(xiàn)在IE和FF下面對屬性_pNod.childNodes.length,即子節(jié)點的數(shù)量解釋不同,在IE中為4,而在FF中為5。得到這樣的結(jié)果是因為兩種瀏覽器對文檔中換行產(chǎn)生的文本節(jié)點的解釋不統(tǒng)一造成的,IE沒有把父節(jié)點與子節(jié)點之間那個換行作為一個文本節(jié)點,如果要使用這個屬性就不得不在HTML文檔編寫的時候避免出現(xiàn)換行,可以將上面的結(jié)構(gòu)改為下面的形式:
- <dividdivid="Div1">
 - <spanidspanid="sp1">節(jié)點1</span>
 - <spanidspanid="sp2">節(jié)點2</span></div>
 
雖然這樣寫以后FF和IE都能很好地統(tǒng)一解釋為兩個子節(jié)點,但是損失了文檔的美觀性和易讀性,所以一般都不推薦使用訪問子節(jié)點的方法來引用節(jié)點。
類似的previousSibling和nextSibling也存在類似的問題。這兩個屬性是用來引用上一個或者下一個兄弟節(jié)點的,使用這兩個屬性時也存在空白文本節(jié)點的問題,我們也應該盡量避免使用這兩個屬性。#p#
2.文檔元素節(jié)點的操作
得到一個文檔元素節(jié)點的引用之后,就可以對這個節(jié)點進行一些控制和操作,以達到對HTML顯示進行更新的目的。
(1)DOM標準操作,在DOM模型中定義了一套能夠?qū)ξ臋n結(jié)構(gòu)進行更新的方法,我們可以通過這些方法創(chuàng)建文檔節(jié)點,并將節(jié)點添加到文檔中或者從文檔中刪除。
◆document.createElement(elmName)根據(jù)標記名稱創(chuàng)建一個節(jié)點。
◆document.createTextNode(text)根據(jù)一段文本創(chuàng)建一個文本節(jié)點。
◆node.appendChild(childNode)將節(jié)點添加到一個節(jié)點下子節(jié)點的末尾。
◆node.insertBefor(newNode,oldNode)將節(jié)點插入到指定節(jié)點之前,newNode為新節(jié)點,oldNode為指定的節(jié)點,此節(jié)點必須為node的已經(jīng)存在的一個子節(jié)點。
◆node.Replace(newNode,oldNode)用新節(jié)點取代一個舊節(jié)點,與上面方法類似,oldNode必須為node的一個已近存在的子節(jié)點。
◆node.cloneNode(cloneChild)復制一個節(jié)點,參數(shù)cloneChild是一個布爾值,表示是否復制子節(jié)點。
◆node.removeChild(childNode)刪除一個子節(jié)點,需要注意的是該方法將返回被刪除節(jié)點的引用。
下面我們用一個例子來說明這些方法的使用:
- var_div1=document.getElementById("div1");
 - //獲取Div1節(jié)點var_sp3=document.createElement("span");
 - //創(chuàng)建一個<span>元素節(jié)點_sp3.id="span3";
 - //將新節(jié)點的屬性id設為"span3"var_txt1=document.createTextNode("節(jié)點3");
 - //創(chuàng)建一個文本節(jié)點_sp3.appendChild(_txt1);
 - //將文本節(jié)點添加到新元素節(jié)點下_div1.appendChild(_sp3);
 - //將元素節(jié)點添加到節(jié)點Div1下
 - //此時界面顯示節(jié)點1節(jié)點2節(jié)點3var_sp4=_sp3.cloneNode(true);
 - //將元素節(jié)點復制_sp4.id="span4";
 - //為新復制的節(jié)點設置id屬性var_txt2=document.createTextNode("節(jié)點4");
 - //新建一個文本節(jié)點_sp4.replaceChild(_txt2,_sp4.childNodes[0]);
 - //將節(jié)點_sp4的文本節(jié)點替換_sp3.parentNode.insertBefore(_sp4,_sp3);
 - //將節(jié)點_sp4添加到節(jié)點_sp3之前
 - //此時界面顯示節(jié)點1節(jié)點2節(jié)點4節(jié)點3_sp4.parentNode.removeChild(_sp4);
 - //刪除節(jié)點_sp4
 
(2)Table的操作
我們發(fā)現(xiàn)如果通過以上的方法對表格對象<table>進行操作的話,在IE下將得不到正確的結(jié)果,在IE下必須使用DOM1的方法對表格進行操作。
◆tab.insertRow(idx)在表格指定索引位置添加一行空行,idx為索引位置。
◆tab.deleteRow(idx)在表格指定索引位置刪除一行。
◆row.insertCell(idx)在行的指定索引位置添加一個空單元格。
◆row.deleteCell(idx)在行的指定位置刪除一個單元格。
可以通過document.createElement(“table”)創(chuàng)建一個表格,通過索引器可以訪問talbe的各個行和單元格,如tab.rows[1].cells[3],這樣我們就能得到表格的第二行第四列的引用,我們可以向操作普通節(jié)點一樣來對這個單元格對象進行操作。下面是一個表格操作的例子,假定這個表格原來有2行2列。
- vartab=document.getElementById("tab");
 - //得到對表格的引用varrow2=tab.insertRow(2);
 - //新增第三行varcell20=row2.insertCell(0);
 - //為第三行添加第一個單元格cell20.innerHTML="20";
 - //varcell21=row2.insertCell(1);//為第三行添加第二個單元格cell21.innerHTML="21";
 - tab.rows[1].deleteCell(1);//刪除第二行第二列tab.deleteRow(1);
 - //刪除第二行
 
(3)innerHTML的靈活使用
在IE4.0以后,elm.innerHTML這個屬性得到大部分瀏覽器的廣泛支持,其易用性使得我們對文檔的操作得到了很大程度的簡化,下面來看一個操作文檔節(jié)點的例子,假設要對一個節(jié)點添加兩個子節(jié)點,并設置一些屬性,下面是DOM模型標準創(chuàng)建方法:
- var_div1=document.getElementById("div1");
 - //得到父節(jié)點var_sp1=document.createElement("span");
 - //創(chuàng)建span節(jié)點_sp1.id="span1";
 - var_txt1=document.createTextNode("節(jié)點1");
 - //創(chuàng)建文本節(jié)點_sp1.appendChild(_txt1);
 - //將文本加入到span節(jié)點下_div1.appendChild(_sp1);
 - //將span節(jié)點加入到父節(jié)點下
 
這樣寫我們通過六行代碼完成了功能的實現(xiàn),下面來看使用innerHTML的情況
- var_div2=document.getElementById("div2");
 - _div2.innerHTML="<spanid='span1'>節(jié)點2</span>";
 
運行后發(fā)現(xiàn),只使用了兩行代碼而得到了完全相同的效果,并且這種方法還更為直觀一些,可讀性還更強。可見使用innerHTML屬性,可以更為方便高效地改變文檔結(jié)構(gòu),這使得在大多數(shù)情況下都使用innerHTML來操作文檔,但是標準的DOM模型方法在特定的環(huán)境下也有不可取代的作用,在編碼時要靈活判斷,選擇合適的方法解決問題。
【編輯推薦】
- JavaScript DOM特性與應用詳解
 - HTML DOM入門級知識手冊
 - HTML DOM display屬性語法實例解析
 - 深入了解JavaScript HTML DOM對象
 - 術語匯編 Javascript DOM技術探究
 















 
 
 


 
 
 
 