iT邦幫忙

2025 iThome 鐵人賽

DAY 12
0
Modern Web

小小前端的生存筆記 ver.2025系列 第 12

Day12 - 事件捕獲與冒泡其實是一個青春戀愛物語

  • 分享至 

  • xImage
  •  

本文同步發布於個人部落格

這個概念其實沒那麼難~
本質其實就是使用者互動到 DOM 元素提交回應的一個雙向過程而已。

他雖然是 JS 裡一個很基礎、必須知道的知識,但實務上它可能是個小透明,因為現在的框架都會幫忙處理好這些事情。
但面試偶爾還是會考一下這個概念,所以還是得把它記起來。

事件捕獲 & 事件冒泡

先說一下,HTML 的格式基本就是一個元素嵌著一個個元素,這樣層層相扣的結構。
了解事件捕獲與事件冒泡時可以把 DOM tree 想像成很多房間,每個房間裡面都還有其他房間,也許會好懂一些。

<div class="room1">
  <div class="room2">
    <div class="room3">
      <div class="room4">
        <button> Click! </button>
      </div>
    </div>
  </div>
</div>

所以看著上面的結構我們開始來想像,什麼是事件捕獲 (Event Capturing)。
因為 room1 是最外層的房間,所以當使用者點擊了 button 時,雖然看似點擊了 room4 裡的 button,但實際上這個事件會從最外層的 room1 開始捕獲,然後一路往裡面傳遞到 room4 的 button。
那是一個一瞬間的事,想像使用者提交一個互動事件給 room1 的守衛時,他非常迅速地把這個事件傳遞給了 room2 的守衛,然後一路傳下去到了 button。

那 button 接收到事件後總得回應吧? (BTW,接受到事件的當下其實稱為目標階段)
所以 button 會開始丟回他接收到事件的信號,一路從 button 傳遞回 room1。
在傳遞這個回程訊號期間,如果經過的 DOM 元素有 eventHandler,就會被觸發執行,比如:

<div class="room1">
  <div class="room2"
    onclick="console.log('room2 clicked')"
  >
    <div class="room3">
      <div class="room4">
        <button
          onclick="console.log('button clicked')"
        >
          Click!
        </button>
      </div>
    </div>
  </div>
</div>

這裡要特別說明一點,原生 JS 預設在冒泡事件階段會觸發事件處理器,但在捕獲階段不會是因為 addEventListener 的第三個參數 options 內的 capture 預設是 false,代表冒泡階段才觸發事件處理器。
反之設為 true,則會在捕獲階段觸發事件處理器。
當然也可以掛兩個事件監聽器 (addEventListener),一個設為捕獲階段,一個設為冒泡階段,這也是沒什麼問題的。
這樣在目標階段時,會先觸發捕獲階段的事件處理器,然後再觸發冒泡階段的事件處理器。

不過實務上已經很少直接使用 addEventListener 了。
在這個 Vue 跟 React 充斥的前端世界,這些東西都被他們包好好的。
所以只要記得:

事件捕獲與冒泡其實本質就是一個雙向溝通的過程

舉個跟標題符合的例子 XD
小 A (使用者) 暗戀小 B (button) 很久了,終於鼓起勇氣寫了一封情書。
但他們之間隔著好幾位同學,於是小 A 將信悄悄遞給身邊的同學,同學再傳給下一位同學,這樣一手一手地傳遞下去,直到信終於送到小 B 手上 (事件捕獲)。
小 B 拿到信的那一刻,心花怒放,立刻喊出:「我收到情書了!」(目標階段的事件處理器觸發)。
接著她馬上寫下「我也喜歡你 ❤️」的回信,沿著同樣的路線,一手一手地從小 B 傳回小 A (事件冒泡)。
在這段回程中,途中經過的某位同學 C 剛好對信的內容很感興趣,忍不住舉手告訴老師:「小 B 收到情書了!」(冒泡階段某 DOM 元素事件處理器觸發)。
所以事件捕獲與冒泡其實是一個青春戀愛物語。


上一篇
Day11 - needTypeCheck ? TypeScript : JavaScript
下一篇
Day13 - JS 的原型鍊又在說什麼故事?
系列文
小小前端的生存筆記 ver.202527
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言