什麼是 DOM
文檔對象模型 ( Document Object Model ) 是 HTML 和 XML 文檔的編程接口。它提供了對文檔的結構化的表述,並定義了一種方式可以從程序中對該結構進行訪問,從而改變文檔的結構,樣式和內容。DOM 將文檔解析爲一個由節點和對象 ( 包含屬性和方法 ) 組成的結構集合。簡言之,它會將 WEB 頁面和腳本或程序語言來連接起來
一個 WEB 頁面是一個文檔,這個文檔可以在瀏覽器窗口或作爲 HTML 源碼顯示出來。但上述兩個情況中都是同一份文檔,文檔對象模型 ( DOM ) 提供了對同一份文檔的另一種表現,存儲和操作的方式。DOM 是 WEB 頁面的完全面向對象的表述,它能夠使用如 JavaScript 等腳本語言進行修改
什麼是 HTML DOM
HTML DOM 是 HTML 的標準對象模型和編程接口,它定義了:
- 作爲對象的 HTML 元素
- 所有 HTML 元素的屬性
- 訪問所有 HTML 元素的方法
- 所有 HTML 元素的事件
通過這個對象模型,JavaScript 可以獲得創建動態 HTML 的所有力量:
- JavaScript 能改變頁面中的所有 HTML 元素
- JavaScript 能改變頁面中的所有 HTML 屬性
- JavaScript 能改變頁面中的所有 CSS 樣式
- JavaScript 能刪除已有的 HTML 元素和屬性
- JavaScript 能添加新的 HTML 元素和屬性
- JavaScript 能對頁面中所有已有的 HTML 事件作出反應
- JavaScript 能在頁面中創建新的 HTML 事件
DOM 操作
HTML DOM 節點
在 HTML DOM 中,每一個元素都是 節點
- 文檔是一個文檔節點
- 所有的 HTML 元素都是元素節點
- 所有的 HTML 屬性都是屬性節點
- 文本插入到 HTML 元素是文本節點
- 註釋是註釋節點
Document 對象
當瀏覽器載入 HTML 文檔,它就會成爲 Document 對象
Document 對象是 HTML 文檔的根節點
Document 對象使我們可以從腳本中對 HTML 頁面中的所有元素進行訪問
常用屬性
屬性 | 描述 |
---|---|
document.activeElement | 返回當前獲取焦點元素 |
document.cookie | 設置或返回與當前文檔有關的所有cookie |
document.body | 返回當前文檔的 body 元素 |
document.baseURL | 返回文檔的絕對基礎URL |
document.documentElement | 返回文檔根節點 |
document.domain | 返回當前文檔的域名 |
document.forms | 返回當前文檔中所有 Form 對象引用 |
document.images | 返回當前文檔中所有 image 對象引用 |
document.links | 返回文檔中所有鏈接對象引用 |
document.head | 返回文檔 head 元素 |
document.referrer | 返回載入當前文檔的文檔URL |
document.title | 返回當前文檔的標題 |
document.URL | 返回文檔完整URL |
document.readyState | 返回當前文檔加載狀態 |
document.characterSet | 返回當前文檔使用的字符集 |
獲取元素
(1) 通過 id屬性 獲取元素對象
返回值爲 元素對象
var oDiv = document.getElementById("id值");
(2) 通過 標籤名字 獲取元素對象
返回值爲 元素數組
var oDiv = document.getElementsByTagName("標籤名");
(3) 通過 class屬性 獲取元素對象
返回值爲 元素數組
var oDiv = document.getElementsByClassName("class值")
(4) 通過 name值 獲取元素對象
返回值爲 元素數組
var oDiv = document.getElementsByName("name值")
(5) 通過 CSS選擇器 獲取元素對象
# 返回文檔中匹配 CSS選擇器 的第一個元素
document.querySelector("CSS選擇器")
# 返回文檔中匹配 CSS選擇器 的所有元素
document.querySelectorAll("CSS選擇器");
Element對象
元素對象 ( Element ) 代表着一個 HTML 元素
元素對象的 子節點 可以是 元素節點,文本節點,註釋節點
基本屬性
屬性 | 描述 |
---|---|
element.attributes | 返回元素的屬性數組 |
element.offsetHeight | 返回元素的高度(包括border和padding) |
element.offsetWidth | 返回元素的寬度(包括border和padding) |
element.offsetLeft | 返回元素距離父元素左側的距離(父元素需要具備定位屬性) |
element.offsetTop | 返回元素距離父元素頂部的距離(父元素需要具備定位屬性) |
屬性修改
函數 | 描述 |
---|---|
element.hasAttributes() | 判斷元素是否具有屬性 |
element.hasAttribute(attr) | 判斷元素是否具有指定屬性 |
element.setAttribute(attr,value) | 給元素設置屬性 |
element.getAttribute(attr) | 獲取指定屬性 |
element.removeAttribute(attr) | 刪除指定屬性 |
節點操作
屬性 | 描述 |
---|---|
element.children | 返回元素子元素節點 |
element.firstElementChild | 返回元素第一個元素節點 |
element.lastElementChild | 返回元素最後一個元素點 |
element.previousElementSibling | 返回元素上一個兄弟元素 |
element.nextElementSibling | 返回元素下一個兄弟元素 |
element.parentNode | 返回元素父節點 |
element.hasChildNodes() | 判斷元素是否具有子元素 |
樣式操作
1. element.style 讀取/修改樣式
// 獲取元素對象
var div = document.getElementById("div");
// 獲取樣式
console.log(div.style.backgroundColor)
// 修改樣式
div.style.backgroundColor = "red";
2. getComputedStyle 獲取樣式
// 獲取元素對象的 CSS樣式 數組
var style = window.getComputedStyle(元素對象[,"僞類"]);
console.log(style);
兩者區別
-
只讀和讀寫
getComputedStyle
方法是隻讀的,只能獲取樣式,不能設置;element.style
能讀能寫
-
獲取屬性的範圍
getComputedStyle
方法獲取的是最終應用在元素上的所有 CSS屬性對象;element.style
只能獲取 style 屬性中的 CSS樣式。
對於一個光禿禿的元素 <p>
,element.style
在獲取樣式方面就不如 getComputedStyle
方法了!
文本操作
屬性 | 描述 |
---|---|
element.innerHTML | 設置和查看標籤內容,包含 HTML 格式 |
element.innerText | 設置和查看標籤內容,僅支持純文本內容 |
元素/節點 增刪
創建標籤
var btu = document.createElement("button");
創建文本節點
var text = document.createTextNode("hello");
克隆節點
cloneNode(deep)
克隆一個節點,deep 設置爲 true 將遞歸克隆內部節點
// 獲取 div 元素
var div = div.insertBefore(h1,div.firstChild);
// 克隆 div 元素
var new_div = div.cloneNode()
添加節點
appendChild(node)
添加一個節點到末尾
// 創建一個 h1 標籤
var h1 = document.createElement("h1");
// 創建一個 文本節點
var text = document.createTextNode("hello");
// 將 文本節點 添加到 h1標籤中
h1.appendChild(text);
插入節點
insertBefore(new_node,old_node)
插入一個節點到某個節點之前
// 創建一個 h1 標籤
var h1 = document.createElement("h1");
// 獲取 div 元素
var div = document.getElementById("item");
// 插入 h1 標籤到父節點第一個位置
div.insertBefore(h1,div.firstChild);
刪除節點
removeChild(node)
刪除一個子節點
// 獲取 div 元素
var div = document.getElementById("item");
// 刪除 div 元素最後一個子節點
div.removeChild(div.lastChild)
事件
事件是 JavaScript 與 HTML 交互的基礎,要實現用戶與頁面的交互,先要對目標元素綁定特定的事件,設置事件處理函數,然後用戶觸發事件,事件處理函數執行,產生交互效果
事件類型
在 HTML DOM 中有兩種事件傳播的方法:冒泡和捕獲
事件傳播是一種定義當發生事件時元素次序的方法,假如 <div>
元素內有一個 <p>
,然後用戶點擊了這個 <p>
元素,應該首先傳遞哪個元素的 click 事件?
在冒泡中,最內側元素的事件會首先處理,然後是更外側的:首先處理 <p>
元素的點擊事件,然後是 <div>
元素的點擊事件
在捕獲中,最外側元素的事件會首先被處理,然後是更內側的:首先處理 <div>
元素的點擊事件,然後是 <p>
元素的點擊事件
綁定事件
(1) DOM 0級事件
<button id="btu">提交</button>
<script>
var btu = document.getElementById("btu");
// 綁定事件
btu.onclick = function(){
console.log("hello!");
};
// 解綁事件
btu.onclick = null;
</script>
缺點:無法設置多個事件處理函數
(2) DOM 2級事件
<button id="btu">提交</button>
<script>
var btu = document.getElementById("btu");
// 綁定事件
btu.addEventListener("click",showFn,false);
btu.addEventListener("click",showFn2,false);
function showFn(){
console.log("hello fn1");
};
function showFn2(){
console.log("hello fn2");
}
// 解綁事件
btn.removeEventListener("click",showFn,false);
</script>
可以爲元素綁定多個事件處理函數,可以通過第三個參數設置事件類型,默認爲 false,將使用冒泡傳播,如果設置爲 true,則爲捕獲傳播
Event 對象常見應用
(1) event.preventDefault()
如果調用這個方法,元素默認事件行爲將不再觸發。
什麼是默認事件呢?例如表單 點擊提交按鈕跳轉頁面,a標籤默認頁面跳轉或是錨點定位等
很多時候我們使用 a標籤僅僅是想當做一個普通的按鈕,點擊實現一個功能,不想頁面跳轉
<a id="test" href="http://www.cnblogs.com">鏈接</a>
<script>
var a = document.getElementById("test");
// 此時,點擊a標籤只會打印消息,而不會進行頁面跳轉
a.onclick = function(e){
console.log("點擊了a標籤");
e.preventDefault();
}
</script>
(2) event.stopPropagation()
阻止事件冒泡到父元素
前邊提到事件冒泡是指事件從目標節點自下而上向 window對象傳播的階段,添加 event.stopPropagation()
這句話後,就阻止了父事件的執行
(3) event.stopImmediatePropagation();
即能阻止事件向父元素冒泡,也能阻止元素同事件類型的其它監聽器被觸發
例如,一個按鈕元素綁定了多個 click 事件,當在某個 click() 事件中添加了 event.stopImmediatePropagation();
後,不僅阻止了父事件的執行,還阻止了其它 click 事件的執行
事件代理
由於事件會在冒泡階段向上傳播到父節點,因此可以把子節點的監聽函數定義在父節點上,由父節點的監聽函數統一處理多個子元素的事件,這種方法叫做事件的代理(delegation)
優點:
- 減少內存消耗,提高性能
假設有一個列表,列表之中有大量的列表項,我們需要在點擊每個列表項的時候響應一個事件
如果給每個列表項一一綁定一個函數,那對於內存的消耗是非常龐大的,效率上需要消耗很多性能,藉助事件代理,我們只需要給父容器 ul 綁定方法即可,這樣不管點擊的是哪一個後代元素,都會根據冒泡傳播的傳遞機制,把容器的 click行爲觸發,然後把對應的方法執行,根據事件源,我們可以知道點擊的是誰,從而完成不同的事
- 動態綁定事件
很多時候,我們需要動態的增刪列表項元素,如果一開始給每個子元素綁定事件,那麼在列表發生變化時,就需要重新給新增的元素綁定事件,給即將刪除的元素解綁事件,如果用事件代理就會省去很多這樣的麻煩!