W3C聯合各瀏覽器廠商制訂了標準物件模型,試圖讓各瀏覽器廠商遵合此一模型進行實作,以解決各瀏覽器間物件模型不一致的問題,在新的物件模型中,也對文件操作的功能加以擴充。
簡單來說,在DOM的標準下,一份文件中所有的標籤定義,包括文字,都是一個物件,這些物件以文件定義的結構,形成了一個樹狀結構。例如:
<html>
<head>
<title>首頁</title>
</head>
<body>
<h1>Hello!World!</h1>
<a href="Gossip/index.html">學習筆記</a>
</body>
</html>
<head>
<title>首頁</title>
</head>
<body>
<h1>Hello!World!</h1>
<a href="Gossip/index.html">學習筆記</a>
</body>
</html>
這份HTML文件,會形成以下樹狀的物件結構:
document
(Document)
|-html (HTMLHtmlElement)
|-head (HTMLHeadElement)
| |-title (HTMLTitleElement)
| |-首頁 (Text)
|
|body (HTMLBodyElement)
|-h1 (HTMLHeadingElement
| |-Hello!World! (Text)
|
|-a (HTMLAnchorElement)
|-學習筆記 (Text)
|-html (HTMLHtmlElement)
|-head (HTMLHeadElement)
| |-title (HTMLTitleElement)
| |-首頁 (Text)
|
|body (HTMLBodyElement)
|-h1 (HTMLHeadingElement
| |-Hello!World! (Text)
|
|-a (HTMLAnchorElement)
|-學習筆記 (Text)
上圖右邊的括號,表示每個物件的型態(在Firefox中)。注意,document代表整個文件,而不代表html節點,你可以使用document.childNodes[0]取得html元素,childNodes表示取得子節點,取回的會是NodeList物件,是個類似陣列的物件,可使用索引值來指定取得某個子節點。方便的document.documentElement也可用來取得html元素。如果想取得body元素,也可以透過document.body來取得。注意,文字也會形成樹狀結構中的元素。
儘管你在上面看到的元素形態,有許多都帶有HTML字眼,但DOM並非專屬於HTML的物件模型,DOM API分為兩部份,一個是核心 DOM API,一個是HTML DOM API。核心API是一個獨立的規範,可以任何語言實現,可操作的對象是基於XML的任何文件,你可以在這邊找到DOM核心API的相關資料:
HTML API是核心API的延伸,專門操作HTML,各種物件對應的形態,通常會有個HTML字眼在前頭,你可以在這邊找到HTML DOM API的相關資料:
核心API文件中所有內容都視為節點,包括文件本身,再依類型區分出不同的形態:
Node
|Document
|Element
|Text
|Attr
...
|Document
|Element
|Text
|Attr
...
Document代表整份文件,Element是所有標籤(也是節點),Text代表文字元素(也是節點),詳細的核心DOM類型,可以在這邊找到:
Level 0 DOM 在window物件上有navigator、location、frames、screen、history等與瀏覽器相關的物件,與文件相關的物件,實際上只有document,功能也有限,這個部份納入了DOM標準,成為了DOM的子集,由於這些舊式API都是專屬於HTML,所以你在 Document 的文件上看不到相關操作,而必須在 The HTML DOM Document Object 這個專屬於HTML的DOM API上才可以找到。
同樣地,Element僅定義核心DOM API中元素的操作,而HTMLHeadElement等元素也有一些專屬HTML的API,這在 Element 中找不到,而必須在 The HTML DOM Document Object 等相關類型中尋找。
每個節點都會有nodeName與nodeType特性,前者可以取得節點的名稱,後者可以取得節點型態常數,這個常數用來查找對應的型態名稱,常數與型態名稱的對照可在這篇文件的底下找到:
舉個來說,可以搭配JavaScript,如下顯示出一個網頁的節點與型態:
<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="content-type">
<script type="text/javascript">
window.onload = function() {
var typeNames = [
'',
'[ELEMENT_NODE]',
'[ATTRIBUTE_NODE]',
'[TEXT_NODE]',
'[CDATA_SECTION_NODE]',
'[ENTITY_REFERENCE_NODE]',
'[ENTITY_NODE]',
'[PROCESSING_INSTRUCTION_NODE]',
'[COMMENT_NODE]',
'[DOCUMENT_NODE]',
'[DOCUMENT_TYPE_NODE]',
'[DOCUMENT_FRAGMENT_NODE]',
'[NOTATION_NODE]'
];
function list(parent, indent) {
var nodes = parent.childNodes;
var tree = [];
for(var i = 0; i < nodes.length; i++) {
tree.push(indent + nodes[i].nodeName +
typeNames[nodes[i].nodeType] + '<br>');
tree.push(list(nodes[i], ' ' + indent));
}
return tree.join('');
}
document.getElementById('console').innerHTML =
'document' + typeNames[document.nodeType] +
'<br>' + list(document, ' ');
};
</script>
<title>首頁</title>
</head>
<body>
<h1>Hello!World!</h1>
<a href="https://openhome.cc/Gossip/">學習筆記</a>
<div id="console"></div>
</body>
</html>
有趣的是,那些在標籤中用來換行與縮排的文字,在Firefox中亦視為文字節點,但Internet Explorer中卻不是,所以你在兩個瀏覽器中會看到不同的結果。