iT邦幫忙

2021 iThome 鐵人賽

DAY 20
0
Modern Web

JavaScript 基礎修練系列 第 20

[Day20] JavaScript - Event Bubbling (事件冒泡) & Event Capturing (事件捕獲)

Event Flow 事件流

DOM的Event flow概念,指的是「網頁元素接收事件的順序」。

假如有兩個重疊的<div>,外層是outer內層是inner:
https://ithelp.ithome.com.tw/upload/images/20210920/20141293JdPW301DHG.png

由於inner被包在outer裡面,所以當我們點擊inner時,也代表我們也點擊到了outer;若再將範圍擴大,實際上我們也點擊了整個網頁。

事件冒泡 & 捕獲

而上面這樣子的事件傳播概念即是Event Flow - 事件流,Event Flow可分為以下兩種方式:

  • 事件冒泡 (Event Bubbling): 從啟動事件的元素節點開始,逐層往外傳遞,直到整個網頁的根節點,也就是 document。
  • 事件捕獲 (Event Capturing): 由 DOM 樹的最外層(document)依序向內,逐漸往下傳遞,直到啟動事件的元素點。

當 DOM 事件發生時,事件會先由外到內 (capturing phase)、再由內到外 (bubbling phase) 的順序來傳播。

根據 W3C 所定義的 Event Flow:
https://www.w3.org/TR/DOM-Level-3-Events/images/eventflow.svg

如下範例:

<html>
    <head>
        <title>Event flow</title>
    </head>
    <body>
        <div>
            <ul>
                <li></li>
            </ul>
        </div>
    </body>
</html>
  • 當使用者點擊 li 元素時,事件觸發的順序是:
    • Capturing 捕捉階段:document -> <html> -> <body> -> <div> -> <ul> -> <li>
    • Bubbling 氣泡階段:<li> -> <ul> -> <div> -> <body> -> <html> -> document
  • DOM 中的元素會按照上面的順序依序地觸發其 click 事件。

另外,在 addEventListener 和 removeEventListener 方法中,可以傳遞第三個參數(布林值),用來指定事件處理函數是要在 Capturing 階段或 Bubbling 階段被執行。

如果是false就用事件冒泡(bubbling),如果是true就使用事件捕捉(capturing)。
沒寫的話,預設就是false,也就是預設使用事件冒泡(bubbling)機制:

element.addEventListener('click', eventHandler) // 未指定,預設為冒泡
element.addEventListener('click', eventHandler, false) // 冒泡
element.addEventListener('click', eventHandler, true) // 捕獲

 
 範例

<div id="parent">
  父元素
  <div id="child">子元素</div>
</div>
var parent = document.getElementById("parent");
var child = document.getElementById("child");

parent.addEventListener("click", function() {
  console.log("Parent capturing")
}, true);

parent.addEventListener("click", function() {
  console.log("Parent bubbling")
}, false);

child.addEventListener("click", function() {
  console.log("Child capturing")
}, true);

child.addEventListener("click", function() {
  console.log("Child bubbling")
}, false);
  • 當點擊子元素時,console.log的結果為:
    Parent capturing
    Child capturing
    Child bubbling
    Parent bubbling

  • 當點擊父元素時,console.log的結果為:
    Parent capturing
    Parent bubbling

以上結果可見,當點擊子元素時,會先從外層的父元素開始傳遞,再到內層子元素,再從子層回到父層。

 
 
 

參考資料:
https://www.fooish.com/javascript/dom/event.html
https://ithelp.ithome.com.tw/articles/10191970


上一篇
[Day19] JavaScript - DOM Event
下一篇
[Day21] JavaScript - Event object (事件物件)
系列文
JavaScript 基礎修練30

尚未有邦友留言

立即登入留言