JS事件傳遞機制

Share This Post

事件分為三個階段,

1:Capturing Phase 捕獲階段
2:Target Phase     傳遞到元素本身
3:Bubbling Phase   冒泡階段

完整事件流

事件冒泡

由事件目標依序向外傳遞,過程中觸發各別元素的監聽事件。(逐層往上傳遞,直到整個網頁的根節點,也就是 document->Window。)
注意:大部分事件都會冒泡

w3c事件冒泡定義

範例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Event Bubbling</title>
</head>
<<body id ="body">  
    <div id = "lay1">
        <div id = "lay2">
          <button id="clickMe">Click Me</button>
        </div>
    </div>
    <script>
        let  button = document.getElementById('clickMe');
        let div1= document.getElementById('lay1');   
        let div2= document.getElementById('lay2');
        button.onclick = function() {
          console.log('Button active');
        };
        div1.onclick=function(){
            console.log("div1 active");
        }
        div2.onclick=function(){
            console.log("div2 active");
        }
        document.body.onclick = function() {
          console.log('body active');
        };
        document.onclick = function() {
          console.log('document active');
        };
        window.onclick = function() {
          console.log('window active');
        };
    </script>
</body>
</html>

以上架構來講的話,冒泡事件順序是
button>lay2>lay1>body>document>window

輸出結果

事件捕獲

另一種事件流稱為事件捕獲,與事件冒泡相反,DOM 的事件會從(window) 開始往下尋找目標 (target)。是一個找尋過程

addEventListener第三個參數 useCapture,根據文檔設為True時,在事件冒泡時不會啟動函數等於是在事件捕獲階段就會啟動函數,預設值為False,則為在事件冒泡時才會啟動函數。

mdn-addEventListener
w3c事件捕獲定義

addEventListener(type, listener);
addEventListener(type, listener, options);
addEventListener(type, listener, useCapture);

    //刪除下列三行
    document.body.onclick=function()
        console.log('window active');
    };
    
    //改為下列三行
    document.body.addEventListener('click', function() {
        console.log('body   active');
    },true);

事件觸發結果會是?

注意:感謝你的注意

冒泡還是捕獲?

程式會執行哪個?答案是兩個都會執行,但是在實際執行事件操作時,通常是由冒泡來執行,且大部分都事件會冒泡

事件代理

假設今天需要獲取某個li的資料,必須監聽每個li,如果li數量不多的情況下,看不太出區別,但只要數量一多使用平常的方法必會降低效能,所以有一種方法叫做事件代理,這邊是指一種寫法而不是一種語法,是用父級的元素做事件處理,當子級的元素被觸發,根據事件冒泡的流程,會跑到父級,這麼設定的話父級被點擊也會被觸發,不用擔心,可以使用target設定來規避這個問題。
w3c事件代理

範例

<ul id="parent-list">
      <li id="item_1">Item 1</li>
      <li id="item_2">Item 2</li>
      <li id="item_3">Item 3</li>
      <li id="item_4">Item 4</li>
      <li id="item_5">Item 5</li>
      <li id="item_6">Item 6</li>
    </ul>
// Get the element, add a click listener...
        document.getElementById("parent-list").addEventListener("click", function(e) {
        // e.target is the clicked element!
        // If it was a list item
        if(e.target && e.target.nodeName == "LI") {
        // List item found!  Output the ID!
        alert("List item " + e.target.id.replace("item_", "") + " was clicked!");
        }
});

訂閱研究文章

Get updates and learn from the best

<