JS筆記之DOM事件模型

1、DOM事件模型
包括 捕獲冒泡(IE用的是事件冒泡),捕獲是從上(window)往下到達目標元素,冒泡則是相反,從當前元素往上到 window。
事件模型

2、DOM事件流
瀏覽器在當前窗口頁面與用戶做交互的過程中,比如點擊了鼠標左鍵,這個點擊是怎麼觸發傳到頁面上的目標元素?
這就要經過事件流,整個事件流分三個階段:
第一階段是 捕獲,事件從上(window)往下的過程;
第二階段是 目標階段,如點擊某個目標元素,事件通過捕獲到達目標元素,就是目標階段;
第三個階段是 冒泡,從目標元素再上傳到window對象,就是冒泡的過程。
事件流

(1)DOM事件捕獲流程
在這裏插入圖片描述

捕獲是從上到下:
第一個真正接收的是window(對象)
第二個接收的是document(對象)
第三個接收的是html標籤(如何獲取到html標籤?答案是通過 document.documentElement)
第四個接收的是body(document.body)
(父級–子級,剩下的就是按照普通的html結構一層一層往下傳)
最後到達目標元素。

(2)DOM事件冒泡流程

與事件捕獲正好相反,冒泡是從目標元素從下往上,最終到達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>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章