文檔對象模型是用於HTML和XML文檔的應用程式編程介面,它定義文檔的邏輯結構,以及訪問和操作文檔的方式。 ...
官方定義——應用程式編程介面(API)
文檔對象模型是用於HTML和XML文檔的應用程式編程介面,它定義文檔的邏輯結構,以及訪問和操作文檔的方式。
"The Document Object Model (DOM) is an application programming interface (API) for HTML and XML documents. It defines the logical structure of documents and the way a document is accessed and manipulated." —— W3C DOM
“文檔對象模型是用於HTML和XML文檔的應用程式編程介面”
應用程式編程介面(Application Program Interface,簡稱API),就是“提供商”將一個功能的具體實現(業務邏輯)封裝起來,只暴露給“客戶”可供調用的編程介面。如果客戶想使用某一功能,則只需調用該功能對應的編程介面,而無需關註於具體實現。打個比方,海爾生產空調,你購買空調後按照說明書操作空調就好,不需要知道空調是根據什麼原理造出來的。
對於DOM而言,“提供商”指的就是實現DOM的開發者(比如,開發JavaScript引擎V8的工程師),“客戶”指的就是使用DOM的開發者(比如,開髮網站的前端工程師)。他們之間共同遵守的就是DOM規範。
因此,DOM規範同時約束它的實現者和使用者。DOM實現者必須實現規範中定義的所有介面,DOM使用者應該調用規範中相應的介面實現相應的功能。
如果你是實現者,需要關註如何實現DOM API;如果你是使用者,則只需關註如何使用DOM API。
“它定義文檔的邏輯結構,以及訪問和操作文檔的方式”
上面這句話對 DOM API 作了更具體的解釋,包括三層意思:
- 定義文檔的結構
- 訪問文檔的方式
- 操作文檔的方式
HTML DOM 是對 DOM Core 的擴展,添加了專門針對 HTML 文檔的特定對象和方法,它與現有的文檔對象模型一致。下麵我們就來討論如何使用 HTML DOM API 的問題。
一、如何定義文檔的邏輯結構?——節點對象樹
DOM規範,將網頁中的HTML文檔抽象為記憶體中的節點對象樹(DOM Tree)。樹中的每一個節點對象對應HTML文檔中的一個元素。
二、如何訪問文檔?——訪問節點對象
(0) Document 介面作為文檔入口
Document 介面代表整個文檔。JavaScript 中的全局對象 document 是對 Document 介面的實現。
(1) 直接訪問文檔中的節點對象。
方法 | 描述 |
document.getElementsById("id"); | 通過 id 屬性獲取節點對象 |
document.getElementsByName("name"); | 通過 name 屬性獲取節點對象 |
document/element.getElementsByTagName("tag"); | 通過 tag 屬性獲取節點對象 |
document/element.getElementsByClassName("class1[ class2]"); | 通過 class 屬性獲取節點對象 |
document/element.querySelector("selector"); | 通過 css 選擇器 獲取首個節點對象 |
document/element.querySelectorAll("selector"); | 通過 css 選擇器 獲取所有節點對象 |
(2) 通過節點關係訪問一個節點周圍的節點對象。
關係 | 屬性 | 描述 |
父節點(parent node) | parentNode/parentElement | 獲取所屬父節點對象 |
ownerDocument | 獲取節點所屬文檔節點(根節點)對象 | |
兄弟節點(sibling nodes) | nextSibling nextElementSibling | 獲取前一個兄弟節點對象 獲取前一個兄弟元素節點對象 |
previousSibling previousElementSibling | 獲取後一個兄弟節點對象 獲取後一個兄弟元素節點對象 | |
子節點(child nodes) | childNodes children | 獲取所有子節點對象 獲取所有子元素節點對象 |
hasChildNodes(); | 判斷是否包含子節點對象 | |
childElementCount | 獲取子元素節點對象數量 | |
firstChild firstElementChild | 獲取第一個子節點對象 獲取第一個子元素節點對象 | |
lastChild lastElementChild | 獲取最後一個子節點對象 獲取最後一個子元素節點對象 |
三、如何操作文檔?——操作節點對象
思路一:【節點對象】首先是一個【對象】,只要是對象就具有【屬性】和【行為】。
元素節點p作為對象,id,class,style(該屬性是一個對象)等作為對象的屬性,onclick,onfocus,oninput 等作為對象的行為,具體的動作由 JavaScript 代碼控制。
思路二:節點對象只包含屬性 —— 特性屬性、樣式屬性和行為(事件)屬性。
將【行為】看作對象的一種屬性,以下實例印證了這一觀點:
我們獲取節點對象的目的,就是為了操作節點對象本身以及節點對象的屬性。
(0) 操作節點對象本身
操作 | 方法 | 描述 |
創建節點 | document.createElement("TAG"); document.createTextNode("#文本"); document.createComment("#註釋"); document.createDocumentFragment(); document.createAttribute("myAttrName"); | 創建一個元素節點 創建一個文本節點 創建一個註釋節點 創建一個空白的文檔片段節點 |
插入節點 | parentNode.appendChild(newChild); parentNode.insertBefore(newChild,refChild); | 插入子節點(作為最後子節點) 插入子節點(在指定子節點之前) |
刪除節點 | parentNode.removeChild(oldChild); | 刪除指定的子節點 |
替換節點 | parentNode.replaceChild(newChild,oldChild); | 替換一個子節點 |
克隆節點 | node.cloneNode(deep); | 克隆一個節點 |
(1) 操作節點對象的特性屬性
方法 | 描述 |
e.特性名稱[="value"]; | 獲取/設置特性值 |
e.getAttributeNames(); | 獲取已設置的全部屬性名稱(非IE內核) |
e.getAttribute("特性名稱"); | 獲取特性值 |
e.getAttributeNode("特性名稱"); | 獲取特性節點[特性名稱=特性值] |
e.setAttribute("特性名稱","特性值"); | 設置特性值(不存在時新建該屬性) |
e.setAttributeNode(Attr); |
(2) 操作節點對象的樣式屬性
方法 | 描述 |
e.style.color[ ="顏色值"] | 獲取/設置標簽內樣式(內嵌樣式) |
window.getComputedStyle(e).color; document.defaultView.getComputedStyle(e).color; | 獲取包括內嵌樣式、<style>、<link>在內的最終樣式(非IE內核 或 IE>8) |
e.currentStyle.color | 獲取包括內嵌樣式、<style>、<link>在內的最終樣式(IE內核) |
(3) 操作節點對象的行為(事件)屬性
方法 | 描述 |
e.onclick[ =fun()]; e.onclick(); | 獲取/設置事件 觸發事件 |
e.addEventListener("type",listener,[useCapture]); | 註冊事件(非IE內核 或 IE>8) |
e.attachEvent("ontype",listener); | 註冊事件(IE內核<11) |
e.removeEventListener("type",listener,[useCapture]); | 移除事件(非IE內核 或 IE>8) |
e.detachEvent("ontype",listener); | 移除事件(IE內核<11) |
e.dispatchEvent(event) | 調度(觸發)事件 |
(4) 操作節點對象的內容(屬性)
節點對象的內容,實際上是節點對象的子節點。傳統的方法是使用新創建的子節點替換需要修改的舊子節點。
<html> <body> <div> <p>第一個段落</p> <p>第二個段落</p> </div> </body> </html>
<script> //獲取父節點 var d = document.querySelector("div"); //獲取需要替換的舊子節點 var oldChild = d.firstChild; //創建新子節點 var newChild = document.createTextNode("新的文本"); //替換 d.replaceChild(newChild ,oldChild ); </script>
如此常用的操作,卻有如此繁瑣的操作過程,況且一次只能替換一個子節點,這也太坑了吧!別急,DOM 規範為我們提供了更加簡便的操作。
轉換一下思路,我們將節點對象的內容看作是節點對象的一個屬性。那麼方法 e.innerHTML 屬性將以字元串的形式返回所有節點對象的內容。 e.innerHTML = newStr 將替換該內容。newStr 可以包含tag,替換的內容會自動轉換為節點對象(其實簡單的文本字元串,也會轉換成一個文本節點)。
<script> //獲取節點 var d = document.querySelector("div"); //修改節點內容 var str = "新的文本"; d.innerHTML= str; </script>
最終的節點對象應該是下麵這張圖:
【The End】