1、DOM事件模型
包括 捕獲 和 冒泡(IE用的是事件冒泡),捕獲是從上(window)往下到達目標元素,冒泡則是相反,從當前元素往上到 window。
2、DOM事件流
瀏覽器在當前窗口頁面與用戶做交互的過程中,比如點擊了鼠標左鍵,這個點擊是怎麼觸發傳到頁面上的目標元素?
這就要經過事件流,整個事件流分三個階段:
第一階段是 捕獲
,事件從上(window)往下的過程;
第二階段是 目標階段
,如點擊某個目標元素,事件通過捕獲到達目標元素,就是目標階段;
第三個階段是 冒泡
,從目標元素再上傳到window對象,就是冒泡的過程。
捕獲是從上到下:
第一個真正接收的是window(對象)
第二個接收的是document(對象)
第三個接收的是html標籤(如何獲取到html標籤?答案是通過 document.documentElement)
第四個接收的是body(document.body)
… (父級–子級,剩下的就是按照普通的html結構一層一層往下傳)
最後到達目標元素。
與事件捕獲正好相反,冒泡是從目標元素從下往上,最終到達window(對象)。
3、DOM事件綁定
DOM2級事件定義了 addEventListener
用來綁定事件,該方法中包含三個參數:
element.addEventListener(type,listener,useCapture); // element:要綁定函數的對象
type:事件名稱,要注意的是"onclick"要改爲"click",“onblur"要改爲"blur”,也就是說事件名不要帶"on"
listener :要綁定的函數,當使用聲明式函數時,注意函數名後不用帶括號
useCapture:布爾值,表示是否在捕獲時觸發執行事件處理函數,默認是false,只在冒泡階段觸發,不在捕獲階段觸發
4、DOM事件解綁
通過 addEventListener
添加的事件處理程序只能使用 removeEventListener
來移除,移除時傳入的參數與添加處理程序時使用的參數相同。
這意味着通過 addEventListener
添加的 匿名函數
無法移除:
var btn = document.getElementById("btn");
btn.addEventListener("click", function () {}, false);
btn.removeEventListener("click", function () {}, false); // 移除無效
以上看似傳入了相同的函數,但實際上它們是不同的函數,正確的應該使用以下方式解除事件綁定:
var btn = document.getElementById("btn");
function handler() {};
btn.addEventListener("click", handler, false);
btn.removeEventListener("click", handler, false); // 移除有效
如果瀏覽器不支持 removeEventListener() 方法,可以使用 detachEvent() 方法實現:
var el = document.getElementById("myDIV");
if (el.removeEventListener) { // 所有瀏覽器,除了 IE 8 及更早IE版本
el.removeEventListener("mousemove", myFunction);
} else if (el.detachEvent) { // IE 8 及更早IE版本
el.detachEvent("onmousemove", myFunction); // 綁定事件則是 attachEvent
}
5、DOM事件阻止冒泡
阻止DOM事件冒泡,可以使用event.stopPropagation()方法,這樣點擊子元素就不會往上冒泡到父元素了。
兼容性的寫法:
// if (event.stopPropagation) // 非IE
// event.stopPropagation();
// else
// event.cancelBubble = true;
// if (event.preventDefault)
// event.preventDefault();
// else
// event.returnValue = false;
event.stopPropagation && event.stopPropagation() || (event.cancelBubble = true);
event.preventDefault && event.preventDefault() || (event.returnValue = false); // IE
6、DOM事件響應優先級
event.stopImmediatePropagation();
這個有什麼用呢?
比如有多個相同類型事件的事件監聽函數綁定到同一個元素,當該類型的事件觸發時,它們會按照被添加的順序執行。
但如果我在其中某個監聽函數執行了 event.stopImmediatePropagation() 方法,則當前元素剩下的監聽函數將不會被執行。
<div>
<button id="btn" type="button"></button>
</div>
<script>
var btn = document.getElementById("btn");
btn.addEventListener("click", (event) => {
alert("我是button按鈕上被綁定的第一個監聽函數");
}, false);
btn.addEventListener("click", (event) => {
alert("我是button按鈕上被綁定的第二個監聽函數");
event.stopImmediatePropagation();
// 執行stopImmediatePropagation方法,阻止click事件冒泡,並且阻止button按鈕上後面綁定的其他click事件的事件監聽函數的執行(除了第一個監聽函數)
}, false);
btn.addEventListener("click", (event) => {
alert("我是button按鈕上被綁定的第三個監聽函數");
// 該監聽函數排在上個函數後面,該函數不會被執行
}, false);
document.querySelector("div").addEventListener("click", (event) => {
alert("我是div元素,我是button按鈕的上層元素");
// button按鈕的click事件沒有向上冒泡,該函數不會被執行
}, false);
</script>