iT邦幫忙

2023 iThome 鐵人賽

DAY 28
0
自我挑戰組

複習 JavaScript 核心概念系列 第 28

[Day 28] 事件的傳遞機制

  • 分享至 

  • xImage
  •  

昨天提到可以在 HTML 的 DOM 元素上添加事件監聽器,而今天要來講事件的傳遞機制。在 JavaScript 中,事件冒泡(event bubbling)事件捕獲(event capturing) 是事件傳播中的扮演重要角色。當一個事件在 DOM 元素上觸發時,這個事件將由根元素(通常是<html>)向下傳播(捕獲)至目標元素,且由目標元素傳播(冒泡)至父元素。這兩種機制提供了事件監聽器可以選擇的不同階段,來處理事件。

以下是一個事件傳遞的流程圖。 圖片來源


事件冒泡(Event Bubbling)

事件冒泡(Event Bubbling) 是指當事件在 DOM 樹中觸發時,它會從最下層的元素開始,然後冒泡到最上層的元素。透過 addEventListener() 添加的監聽器預設會偵測冒泡階段傳遞的事件。

<div id="parent">
  <button id="child">Click me!</button>
</div>

<script>
  const parent = document.getElementById("parent");
  const child = document.getElementById("child");

  parent.addEventListener("click", () => {
    console.log("Parent clicked!");
  });

  child.addEventListener("click", () => {
    console.log("Child clicked!");
  });
</script>

在這個例子中,當點擊按鈕(id 為 child)時,事件會由子元素往上冒泡的順序傳遞到父元素(id 為 parent),因此會先觸發子元素的監聽器,接著才觸發父元素的監聽器。

點擊按鈕的輸出結果:
Child clicked!
Parent clicked!

事件捕獲(Event Capturing)

事件捕獲(Event Capturing) 與冒泡相反,事件是由最上層的元素向下層元素進行傳遞的。
可透過 addEventListener() 的第三個參數設為 true ,使監聽器偵測捕獲階段傳遞的事件。

<div id="parent">
    <button id="child">Click me!</button>
  </div>
  
  <script>
    const parent = document.getElementById("parent");
    const child = document.getElementById("child");
  
    parent.addEventListener("click", () => {
      console.log("Parent clicked!");
    }, true); // 使用事件捕獲
  
    child.addEventListener("click", () => {
      console.log("Child clicked!");
    }, true);
  </script>

在這個例子中,當點擊按鈕(id 為 child)時,在捕獲階段的事件由父元素(id 為 parent)依序傳遞到子元素,
因此父元素會先偵測捕獲階段的事件。

點擊按鈕的輸出結果:
Parent clicked!
Child clicked!

停止捕獲及冒泡的方法:Event.stopPropagation()

stopPropagation() 是一個在事件常見的方法,它用來停止事件繼續傳遞。

<div id="parent">
  <button id="child">Click me!</button>
</div>

<script>
  const parent = document.getElementById("parent");
  const child = document.getElementById("child");

  parent.addEventListener("click", () => {
    console.log("Parent clicked!");
  });

  child.addEventListener("click", (event) => {
    console.log("Child clicked!");
    event.stopPropagation(); // 停止事件繼續傳遞
  });
</script>

在這個例子中,當點擊按鈕(id 為 child)時,由於在子元素監聽器的回調函式中,透過「event.stopPropagation()」使事件不再繼續傳遞,因此父元素自然不會偵測到此事件了。

點擊按鈕的輸出結果:
Child clicked!

事件代理(Event Delegation)

事件代理(Event Delegation) 是利用事件的冒泡機制,將事件監聽器添加到其父元素上,而不是添加到每個子元素上。這樣做的好處是減少了監聽器的數量,提高了性能,同時也使得在動態生成的子元素上處理事件變得更加容易。

<ul id="parent-list">
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
</ul>

<script>
  const parentList = document.getElementById("parent-list");

  parentList.addEventListener("click", function(event) {
    if (event.target.tagName === "LI") {
      alert(`Item clicked: ${event.target.textContent}`);
    }
  });
</script>

以上是關於事件傳遞機制的概念,包括 事件捕獲事件冒泡stopPropagation() 方法。另外也簡單舉例了透過 事件代理 的設計方式來簡化結構從而提升性能。話說不知不覺也來到了倒數第三天了,剩下兩天應該會來做收尾的東西了。那我們明天見~


上一篇
[Day 27] JavaScript 監聽事件的方式
下一篇
[Day 29] ECMAScript 各版本重點語法
系列文
複習 JavaScript 核心概念30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言