文檔對象模型(DOM)是表示文檔(比如HTML和XML)和訪問、操作構成文檔的各種元素的應用程序接口(API)。一般的,支持Javascript的所有瀏覽器都支持DOM。本文所涉及的DOM,是指W3C定義的標準的文檔對象模型,它以樹形結構表示HTML和XML文檔,定義了遍歷這個樹和檢查、修改樹的節點的方法和屬性。
這個是不是跟XML的結構有點相似呢。不同的是,HTML文檔的樹形主要包含表示元素、標記的節點和表示文本串的節點。 7.4.2、HTML文檔的節點DOM下,HTML文檔各個節點被視爲各種類型的Node對象。每個Node對象都有自己的屬性和方法,利用這些屬性和方法可以遍歷整個文檔樹。由於HTML文檔的複雜性,DOM定義了nodeType來表示節點的類型。這裏列出Node常用的幾種節點類型:
DOM樹的根節點是個Document對象,該對象的documentElement屬性引用表示文檔根元素的Element對象(對於HTML文檔,這個就是<html>標記)。Javascript操作HTML文檔的時候,document即指向整個文檔,<body>、<table>等節點類型即爲Element。Comment類型的節點則是指文檔的註釋。具體節點類型的含義,請參考《Javascript權威指南》,在此不贅述。 Document定義的方法大多數是生產型方法,主要用於創建可以插入文檔中的各種類型的節點。常用的Document方法有:
對於Element節點,可以通過調用getAttribute()、setAttribute()、removeAttribute()方法來查詢、設置或者刪除一個Element節點的性質,比如<table>標記的border屬性。下面列出Element常用的屬性:
Element常用的方法:
Attr對象代表文檔元素的屬性,有name、value等屬性,可以通過Node接口的attributes屬性或者調用Element接口的getAttributeNode()方法來獲取。不過,在大多數情況下,使用Element元素屬性的最簡單方法是getAttribute()和setAttribute()兩個方法,而不是Attr對象。 7.4.3、使用DOM操作HTML文檔Node對象定義了一系列屬性和方法,來方便遍歷整個文檔。用parentNode屬性和childNodes[]數組可以在文檔樹中上下移動;通過遍歷childNodes[]數組或者使用firstChild和nextSibling屬性進行循環操作,也可以使用lastChild和previousSibling進行逆向循環操作,也可以枚舉指定節點的子節點。而調用appendChild()、insertBefore()、removeChild()、replaceChild()方法可以改變一個節點的子節點從而改變文檔樹。 需要指出的是,childNodes[]的值實際上是一個NodeList對象。因此,可以通過遍歷childNodes[]數組的每個元素,來枚舉一個給定節點的所有子節點;通過遞歸,可以枚舉樹中的所有節點。下表列出了Node對象的一些常用屬性和方法: Node對象常用屬性:
Node對象常用方法:
接下來,讓我們使用上述的DOM應用編程接口,來試着操作HTML文檔。 A、遍歷文檔的節點 DOM把一個HTML文檔視爲樹,因此,遍歷整個樹是應該是家常便飯。跟之前說過的一樣,這裏我們提供兩個遍歷樹的例子。通過它,我們能夠學會如何使用childNodes[]和firstChile、lastChild、nextSibling、previousSibling遍歷整棵樹。 例子1-- sample3_1.htm: 例子2 – sample3_2.htm: B、搜索文檔中特定的元素 document.getElementsByTagName()返回文檔中具有指定標記名的全部Element節點數組(也是NodeList類型)。Element出現在數組中的順序就是他們在文檔中出現的順序。傳遞給getElementsByTagName()的參數忽略大小寫。比如,想定位到第一個<table>標記,可以這樣寫:document.getElementsByTagName(“table”)[0]。例外的,可以使用document.body定位到<body>標記,因爲它是唯一的。 getElementsByTagName()返回的數組取決於文檔。一旦文檔改變,返回結果也立即改變。相比,getElementById()則比較靈活,可以隨時定位到目標,只是要實現給目標元素一個唯一的id屬性值。這個我們在《AJAX開發簡略》的“級聯菜單”例子中已經使用過了。 Element對象也支持getElementsByTagName()和getElementById()。不同的是,搜索領域只針對調用者的子節點。 C、修改文檔內容 例子3 -- sample4_1.htm: 第一行 第二行 第三行 例子4-- sample4_2.htm:
例子5 -- sample4_3.htm:
注意,當執行kid1.replaceChild(repKid,kid1.firstChild);的時候,table2的子節點已經被轉移到table1了,table2已經沒有子節點,不能再調用table2的子節點。看看代碼的註釋,試着運行一下,應該就知道文檔是怎麼改變的了。 D、往文檔添加新內容 例子6 – sample5_1.htm:
我們之前說過,<table>的子節點是<tbody>,<tbody>的子節點纔是<tr>,<tr>是<td>的父節點,最後<td>內部的TextNode節點。所以,往<table>增加單元格行要逐級形成,就像往樹裏面添加一個枝椏一樣,要有葉子有徑。看看,這個留言簿是不是很簡單啊。這個例子同時也演示了往<table>表格標記裏面增加內容的另一種方法。 E、使用DOM操作XML文檔 這個例子包含兩個JS函數。loadXML()負責加載XML文檔,其中既包含加載XML文檔的2級DOM代碼,又有實現同樣操作的Microsoft專有API代碼。需要提醒注意的是,文檔加載過程不是瞬間完成的,所以對loadXML()的調用將在加載文檔完成之前返回。因此,需要傳遞給loadXML()一個引用,以便文檔加載完成後調用。 例子中的另外一個函數makeTable(),則在XML文檔加載完畢之後,使用最後前介紹過的DOM應用編程接口讀取XML文檔信息,並利用這些信息形成一個新的table表格。 例子7 -- sample6_1.htm: |
部分源代碼
一 遍歷文檔節點總數
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>統計Element節點總數</title>
<script language="javascript">
<!--
var elementName = "";
function countTotalElement(node){
var total = 0;
if(node.nodeType == 1){
total ++;
elementName = elementName + node.tagName + "/r/n";
}
方法一
var childrens = node.childNodes;
for(var i = 0 ; i < childrens.length; i++){
total += countTotalElement(childrens[i]);
}
方法二
for(var m=node.firstChild; m!=null; m=m.nextSibling){
total += countTotalElement(m);
}
return total;
}
-->
</script>
</head>
<body>
<table width="364" border="1" cellpadding="0" cellspacing="0">
<form action="" name="form1" method="post">
<tr>
<td width="20%"> 用戶名</td>
<td width="80%"> <input type="text" name="input1" value=""></td>
</tr>
<tr>
<td> 密碼</td>
<td> <input type="password" name="password1" value=""></td>
</tr></form>
</table>
<a href="javascript:void(0)" onClick="alert('標記總數:' + countTotalElement(document) + '/r/n 全部標記如下 /r/n' + elementName );elementName='';">開始統計</a>
</body>
</html>
二 搜索文檔中特定的元素
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>定位HTML文檔特定節點</title>
<script language="javascript">
<!--
function countTotal(){
var elements = document.getElementsByTagName("input");
window.alert("input類型節點總數是:" + elements.length);
}
function anchorElement(){
var element = document.getElementById("submit");
window.alert("控件的value是:" + element.value);
}
-->
</script>
</head>
<body>
<table width="364" border="1" cellpadding="0" cellspacing="0">
<form action="" name="form1" method="post">
<tr>
<td width="20%"> 用戶名</td>
<td width="80%"> <input type="text" name="input1" value=""></td>
</tr>
<tr>
<td> 密碼</td>
<td> <input type="password" name="password1" value=""></td>
</tr>
<tr>
<td> </td>
<td><input type="submit" name="Submit" value="提交"></td>
</tr>
</form>
</table>
<a href="javascript:void(0);" onClick="countTotal();">統計input節點總數</a>
<a href="javascript:void(0);" onClick="anchorElement();">定位提交按鈕</a>
</body>
</html>
三 修改文檔內容
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>顛倒節點順序</title>
<script language="javascript">
<!--
function reverseNode(node){
var kids = node.childNodes;
var kidsNum = kids.length;
for( var i=kidsNum - 1; i>=0;i--){
var c=node.removeChild(kids[i]);
node.appendChild(c);
}
}
-->
</script>
</head>
<body>
<p>第一行</p>
<p>第二行</p>
<p>第三行</p>
<input type="button" name="reverseNode" value="顛倒順序" οnclick="reverseNode(document.body)" />
</body>
</html>
實例二
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>顛倒表格行順序</title>
<script language="javascript">
<!--
function reverserTable(){
var node = document.getElementsByTagName("table")[0];
var child = document.getElementsByTagName("tr");
var newChild = new Array();
for(var i=0;i<child.length;i++){
newChild[i]=child[i].firstChild.innerHTML;
}
node.removeChild(node.childNodes[0]);
var header=node.createTHead();
for(var i=0;i<newChild.length;i++){
var headerrow=header.insertRow(i);
var Cell=headerrow.insertCell(0);
Cell.appendChild(document.createTextNode(newChild[newChild.length-i-1]));
}
}
-->
</script>
</head>
<body>
<table width="200" border="0">
<thead>
<tr>
<td>第一行</td>
</tr>
<tr>
<td>第二行</td>
</tr>
<tr>
<td>第三行</td>
</tr>
<tr>
<td>第四行</td>
</tr>
</thead>
</table>
<input type="button" name="reverse" value="開始顛倒" onClick="reverserTable();">
</body>
</html>
實例三
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>顛倒表格行順序</title>
<script language="javascript">
<!--
function replaceContent(){
var table1 = document.getElementsByTagName("table")[0];
var table2 = document.getElementsByTagName("table")[1];
var kid1 = table1.firstChild.firstChild.firstChild;
var kid2 = table2.firstChild.firstChild.firstChild;
var repKid = kid2.firstChild;
try{
kid1.replaceChild(repKid,kid1.firstChild);
}
catch(e){
alert(e);
}
}
-->
</script>
</head>
<body>
<table width="200" border="0">
<tbody>
<tr>
<td>表格一</td>
</tr>
</tbody>
</table>
<table width="200" border="0">
<tbody>
<tr>
<td>表格二</td>
</tr>
</tbody>
</table>
<input type="button" name="reverse" value="開始顛倒" onClick="replaceContent();">
</body>
</html>
四 往文檔中添加新內容
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>添加表格內容</title>
<script language="javascript">
<!--
function insertStr(){
var f = document.form1;
var value = f.str.value;
var text = document.createTextNode(value);
var td = document.createElement("td");
var tr = document.createElement("tr");
var tbody = document.createElement("tbody");
td.appendChild(text);
tr.appendChild(td);
tbody.appendChild(tr);
var parNode = document.getElementById("table1");
parNode.insertBefore(tbody,parNode.firstChild);
}
-->
</script>
</head>
<body>
<form name="form1" method="post" action="">
<input type="text" id="str" name="str" value="" />
<input type="button" name="insert" value="留言" id="insert" οnclick="insertStr();" />
</form>
<table width="400" border="0" cellspacing="0" cellpadding="0" id="table1">
<tbody>
<tr>
<td height="25">網友留言列表:</td>
</tr>
</tbody>
</table>
</body>
</html>
五 使用DOM對象操作XML文檔
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>加載XML文檔</title>
<script language="javascript">
<!--
function loadXml(handler){
var url = "employees.xml";
if(document.implementation && document.implementation.createDocument){
var xmldoc = document.implementation.createDocument("","",null);
xmldoc.οnlοad=handler(xmldoc,null);
xmldoc.load(url);
}
else if(window.ActiveXObject){
var xmldoc = new ActiveXObject("Microsoft.XMLDOM");
xmldoc.onreadystatechange=function(){
if(xmldoc.readyState==4)handler(xmldoc,url);
}
xmldoc.load(url);
}
}
function makeTalbe(xmldoc,url){
var talbe = document.createElement("table");
table.setAttribute("border",1);
table.setAttribute("width","600");
table.setAttribute("class","tab-content");
document.body.appendChild(table);
var caption = "Employee Data from " + url;
table.createCaption().appendChild(document.createTextNode(caption));
var header = table.createThead();
var headerrow = header.insertRow(0);
headerrow.insertCell(0).appendChild(document.createTextNode("姓名"));
headerrow.insertCell(1).appendChild(document.createTextNode("職業"));
headerrow.insertCell(2).appendChild(document.createTextNode("工資"));
var employees = xmldoc.getElementsByTagName("employees)";
for(var i=0;i<employees.length;i++){
var e = employees[i];
var name = e.getAttribute("name");
var job = e.getElementsByTagName("job")[0].firstChild.data;
var salary = e.getElementsByTagName("salary")[0].firstChild.data;
var row=table.insertRow(i+1);
row.insertCell(0).appendChild(document.createTextNode(name));
row.insertCell(1).appendChild(document.createTextNode(job));
row.insertCell(2).appendChild(document.createTextNode(salary));
}
}
-->
</script>
</head>
<body onLoad="loadXml(makeTalbe);">
</body>
</html>