概要
藉助DOM Tree,我們能直接而且簡易的操作HTML頁面上的每個標記內容
DOM技術被Internet Explorer 5.0及以上版本的瀏覽器所支持,它採取一種非常直觀且一致的方式將HTML文檔進行模型化處理,並藉此提供訪問、導航和操作頁面的簡易編程接口。通過DOM技術,我們不僅能夠訪問和更新頁面的內容及結構,而且還能操縱文檔的風格樣式。DOM由W3C組織所倡導,這樣,大多數瀏覽器都將最終支持這項技術。
比較
可以這么說,DOM是從DHTML(Dynamic HTML)對象模型發展而來的。但更準確的說,DOM對象是對DHTML對象模型進行了根本變革的產物。
藉助DHTML對象模型技術,我們能夠單獨地訪問並更新HTML頁面上的對象,每個HTML標記通過它的ID和NAME屬性被操縱,每個對象都具有自己的屬性、方法和事件,通過方法操縱對象,通過事件觸發因果過程。
DOM則要比DHTML對象模型功能更全面,它提供了一個對整個文檔的訪問模型,而不僅僅再局限於單一的HTML標記(Tag)範圍內。DOM將文檔描繪為一個樹形(Tree)結構,Tree的每個節點表現為一個HTML標記或者HTML標記內的文本項。樹形結構精確地描述了HTML文檔中標記間以及文本項間的相互關聯性,這種關聯性包括child(孩子)類型、parent(雙親)類型和兄弟(sibling)類型。
使用DHTML對象模型訪問和更新HTML頁面內容時,不可避免地需要查詢相關技術手冊。因為HTML對象很多,每個HTML對象又有很多的屬性、方法和事件。但是採用DOM技術訪問和更新HTML頁面內容時,任何手冊都可以放在一邊了。首先查看一下HTML原始碼,推算出頁面的Tree結構模型;然後,按照層次結構關係操縱需要的屬性。比如要更新頁面上的文本項內容,如果採用DTHML對象模型,需要使用到innerHTML屬性,但必須要注意並不是所有的HTML對象都支持innerHTML屬性;如果採用DOM技術,只要修改相關Tree節點都具有的nodeValue屬性值即可。
DOM技術使我們可以方便地沿著文檔的樹型結構在上、下以及一側方向做節點導航,從頁面的任何地方開始,使用child、parent或者sibling三種關聯性組成的表達式代表頁面的其他地方。而DTHML對象模型不包含Tree結構,所以也就不具備頁面對象的相互導航功能。當我們從一個標記對象開始時,不可能用關聯表達式來表達相近的標記。雖然對於某些標記,比如 <TABLE> ,DHTML對象模型可以提供特殊的屬性和方法存取相關內容,但實現方式和效果遠不如DOM技術顯得一致化和直觀化。採用DTHML對象模型訪問<TABLE> 中的單元(cell)內容時,首先要查詢手冊確定單元的坐標值i、j,然後再通過表達式tableObj.rows[i].cells[j].innerHTML實現訪問。但對於DOM來說,訪問TABLE每個單元的內容將變得非常簡單,只需要建立一個節點導航表達式就可以。
另外,DOM技術允許我們操縱文檔的Tree結構,這包括創建新節點(nodes)、刪除存在的節點以及在Tree中移動節點。實際上,這就是執行創建新標記(tags)、刪除存在的標記以及在文檔中移動標記的過程。DTHML對象模型則不允許更改文檔結構,我們只能操縱現有的對象。
DOM提供了一套屬性用於導航、訪問和更新文檔內容,其中包括唯讀類型的屬性和可讀寫類型的屬性。
下表是唯讀類型的屬性:
DOM對象屬性返 回 值
FirstChild返回一個對象(Object),表示第一個孩子節點(child node)。
LastChild返回一個對象(Object),表示最後一個孩子節點(child node)。
NextSibling返回一個對象(Object),表示下一個相鄰的兄弟節點。
NodeName返回節點對應的HTML標記。比如:P,Script。對應文本項節點,返回#text。
nodeType返回節點的類型,1表示此節點是標記(tag),2表示屬性(attribute),3表示文本項。
parentNode返回一個對象(Object),表示當前節點的雙親節點(parent node)。
previousSibling返回一個對象(Object),表示前一個相鄰的兄弟節點。
specified返回一個布爾型變數(Boolean),表示是否設定了屬性值(attribute)。
下表是可讀寫類型的屬性:
DOM對象屬性返 回 值
data返回一個字元串,表示文本項節點的值。如果是其他類型節點,返回undefined。
nodeValue返回一個字元串,表示文本項節點的值。如果是其他類型節點,返回null。
下表是DOM中相關屬性集合:
DOM對象屬性返 回 值
attributes表示節點的屬性集合,通過id來訪問,比如attributes.id。
childNodes表示節點的孩子節點集合,通過數組索引方式訪問,比如:childNodes[2]。
與DHTML對象模型相比較,DOM只有一個缺憾:DOM不能支持事件處理,而DTHML對象模型對於文檔對象則擁有一個廣泛的事件處理功能。
重要節點
Element Node : .com"></a> 中href="http:_//ww_w.test.c_om"即是這個a的屬性節點
Text Node : nodeType=3
文本節點 如<span>text</span>中的“text”即是一個文本節點
注意:通過obj.nodeType得到的值就可以判斷訪問到的是哪種節點。
得到指定的元素節點oNode:
document.getElementById(sid)
document.getElementsByName(sname)
document.getElementsByTagName(stagname)
注意:
document是所有節點的父節點。
元素節點的ID要保持唯一不變。
節點name屬性可以重複,但是在IE下getElementsByName對於DIV節點無效,所以不推薦使用。
從一個節點oNode出發訪問相關元素或者文本節點:
oNode.firstChild();
oNode.lastChild();
oNode.previousSibling();
oNode.nextSibling();
oNode.childNodes();
oNode.parentNode();
注意:<div>x<a>y</a>z</div>這個HTML片段.,在FireFox下如果x處為空,也會被認為存在一個空的文本節點,所以在進行DomTree遍歷時要根據nodeType判斷,來確保找到想找的節點
訪問節點oNode的屬性節點
oNode.getAttribute(sName);
oNode.setAttribute(sName,sValue);
展現方式
1、 使用document.write(sHTML) document.writeln(sHTML)
這個相當於PHP的echo()
參數sHTML將被輸出在該語句執行時的位置成為HTML的一部分。
注意:這個方法只可以在文檔載入過程中使用。
2、 使用oNode.innerHTML = sHTML
改變oNode節點內部的innerHTML
注意:
IE下無法改變,<table><tbody><thead><tfoot><tr>這些節點的innerHTML,只能改變<td>的innerHTML
innerHTML非DOM標準的方法,但是FireFox IE等所有瀏覽器都支持,但innerText,outerHTML,outerText就只有IE才支持,所以不要使用。
3、重頭戲,使用Dom方法
創建、複製元素或文本節點:
var newNode = document.createElement(sTag)
var newNode = document.createTextNode([sText])
var newNode = oNode.cloneNode(true) true:複製包含子節點 false:不包含子節點
插入、替換元素或文本節點:
oNode.appendChild(newNode);
oNode.insertBefore(newNode,childNode);
oNode.replaceChild(newNode, childNode)
刪除元素或文本節點
oNode.removeChild(childNode)
注意:
使用第2、3種方法時,操作涉及的已有oNode必須已經完整載入後才可以,比如
<div id="t"><scrīpt>document.getElementById("t")</scrīpt></div>在div元素沒有閉合時就訪問這個div是要嚴格禁止的。
使用第3種方法創建<table>時不能把<tr>直接作為<table>的子節點,必須加一層<tbody> <thead>或者<tfoot>,否則顯示不出來
針對屬性節點,增加和修改都使用oNode.setAttribute()方法即可,刪除沒什麼意義
DOM Tree實例
下面讓我們來對一個簡單的文檔進行分析,最終形成它的DOM結構。要分析的文檔包括3個段落,HTML代碼如下:
<HTML>
<HEAD>
<TITLE> Simple DOM Demo </TITLE>
</HEAD>
<BODY ID="bodyNode"><P ID = "p1Node">This is paragraph 1.</P>
This is the document body
<P ID = "p2Node"> </P>
<P ID = "p3Node"></P>
</BODY>
</HTML>
請注意,從現在開始,我們就要按照Tree結構以及家族關係的方式來看待整個文檔了。 <BODY>標記是Tree的根節點,它包含了4個孩子節點:p1Node、文本項節點(“This is the document body”)、p2Node和p3Node。每個孩子節點或者是一個HTML標記型節點,或者是一個文本項型節點。在一對開始標記和結束標記間的內容屬於這個標記的孩子節點,比如“This is paragraph1”就是p1Node節點的孩子節點,同時它本身也是一個文本項型節點。文本項型節點必須包含一個非空字元,因此,第2段和第3段的孩子節點是不存在的。
這裡有上述HTML文檔的DOM Tree圖示,它能幫助我們更好地理解節點間的相互關係:
HTML中有一些標記不包含關閉括弧,這種情況下,我們可以將下一個緊挨者的標記作為關閉括弧對待。比如<LI>標記可以將緊挨者的<LI>或<UL>標記作為關閉標識。
簡單文檔的節點導航
文檔的DOM Tree結構為每個標記和文本項設定了一個節點,對於任一被分配了ID屬性的節點,都可以作為起始點開始整個Tree的“攀登”。而且,藉助DOM屬性的強大功能,我們可以定址到Tree中的每一個節點。
在繼續講述前,請再次看看上一節中的簡單文檔的HTML原始碼以及它的DOM Tree結構圖。我們可以得知:圖中的箭頭表示了可以到達Tree中其他節點的導航路線;<BODY>標記的ID屬性值是bodyNode,3個<P>標記的ID屬性值依次為p1Node、p2Node和p3Node。下面,我們分別從不同的節點開始,舉例說明如何定址到其他的節點:
起始節點 到達節點 定址表達式
<BODY> p1Node bodyNode.firstChild 或bodyNode.childNodes[0]
p1Node的孩子節點 bodyNode.firstChild.firstChild
文本項節點 bodyNode.childNodes[1]
p3Node BodyNode.childNodes[3] 或bodyNode.lastChild
p1Node 文本項節點 p1Node.nextSibling
p2Node p1Node.nextSibling.nextSibling
p3Node p1Node.nextSibling.nextSibling.nextSibling
p3Node p1Node的孩子節點 p3Node.previousSibling.previousSibling.previousSibling.childNodes[0]
以上列舉的都是從雙親(parent)到孩子或者孩子到孩子方向的定址表達式,藉助我們介紹另外一種導航方向:使用parentNode屬性從孩子到雙親。比如:要從每一個<P>標記開始定址到<BODY>標記,可以使用p1Node.parentNode、p2Node.parentNode或者 p3Node.parentNode。
為了加深對以上節點導航表達式的理解,我們編寫了一段JavaScript代碼,它將顯示出文檔DOM的每個節點的nodeName值。請注意,除了上面舉例的簡單文檔中涉及到的節點外,還包含一個<Script>標記節點。為了不使問題複雜化,代碼中不使用lastChild屬性。代碼如下:
<HTML>
<HEAD>
<TITLE> Simple DOM Demo </title>
<STYLE>TYPE="text/css">
<!--
FORM.tb {display:inline;}
.twidth{width:100%}
.include{ font-size: 75%; font-family: verdana, arial, helvetica;}
.includebig{font-family: verdana, arial, helvetica;}
.includebig A:link { color: blue; }
.includebig A:visited { color: purple; }
.include A:link { color: blue; }
.include A:visited { color: purple; }
.submitter { font-size: 75%; font-family: verdana, arial, helvetica; }
pre.code {color: #660099; margin-left:5%}
address {text-align: right}
body {background:#FFFFFF; margin-left: 5%; margin-right: 5%}
-->
</STYLE>
</HEAD>
<BODY ID="bodyNode"><P ID = "p1Node">This is paragraph 1.</P>
This is the document body
<P ID = "p2Node"> </P>
<P ID = "p3Node"></P>
<SCRIPT LANGUAGE="JavaScript">
alert(
"bodyNode.firstChild.nodeName = " + bodyNode.firstChild.nodeName + "\n" +
"bodyNode.firstChild.data = " + bodyNode.firstChild.data + "\n" +
"bodyNode.childNodes[0].nodeName = " + bodyNode.childNodes[0].nodeName + "\n" +
"bodyNode.childNodes[1].nodeName = " + bodyNode.childNodes[1].nodeName + "\n" +
"bodyNode.childNodes[1].data = " + bodyNode.childNodes[1].data + "\n" +
"bodyNode.childNodes[3].nodeName = " + bodyNode.childNodes[3].nodeName + "\n" +
"bodyNode.childNodes[4].nodeName = " + bodyNode.childNodes[4].nodeName + "\n" +
"p1Node.nextSibling.nodeName = " + p1Node.nextSibling.nodeName + "\n" +
"p1Node.nextSibling.nextSibling.nodeName = " + p1Node.nextSibling.nextSibling.nodeName + "\n" +
"p1Node.nextSibling.nextSibling.nextSibling.nodeName = " + p1Node.nextSibling.nextSibling.nextSibling.nodeName+ "\n" +
"p3Node.previousSibling.previousSibling.previousSibling.childNodes[0].nodeName = " +
p3Node.previousSibling.previousSibling.previousSibling.childNodes[0].nodeName + "\n" +
"p1Node.parentNode.nodeName = " + p1Node.parentNode.nodeName + "\n" +
"p2Node.parentNode.nodeName = " + p2Node.parentNode.nodeName + "\n" +
"p3Node.parentNode.nodeName = " + p3Node.parentNode.nodeName + "\n" +
"bodyNode.firstChild.firstChild.parentNode.parentNode.nodeName = " +
bodyNode.firstChild.firstChild.parentNode.parentNode.nodeName + "\n"
);
</SCRIPT>
</BODY>
</HTML>