[DOM] Event Propagation II : 事件可以委託-Event Delegation

Huge Gun
4 min readMay 10, 2020

--

本篇是個人的筆記之一,也希望對他人了解 Javascript Event Delegation 有幫助,如果不對的地方也能和我說喔!

起因

之前我在回想 this 時,突然產生一個想法,也是在開頭就想提的問題,同時你也能問問自己,問題如下:

event handler 中一樣能用 this,這個 this 跟 event.target 一定相同嗎 ?指向的 100% 就是註冊了 event handler的那個 element 嗎?

經過一番釐清之後…

答案是: NO !

具體原因跟 Event Capture (捕捉) & Bubble(冒泡) 有關,下面會一一來說明過程,再來帶入主題 Event Delegation,這邊會預設你已經對 DOM 的 Event 捕捉及冒泡有些許的理解。

釐清問題的過程 & 詳解

既然前面說到跟 Event Capture(捕捉) & Bubble(冒泡) 有關,我們先來個簡單的例子

我們這邊綁定的 event handler 不使用 arrow function,因為在這個 case 下 this 會被自動指向 window,所以先使用一般 function 來觀察,接著先來看點擊 parent div 時,出來的 log 如下,

Parent - event handle function log

看起來很正常,如預期的一樣印出相同的 element,再來點擊 child 看看

Child - event handle function log

各位會發現 child log 如預期,但是 parent 卻不同,它的 this 依然指向自己沒錯,可是 event.target 卻指向了 child,其原因是 "先捕捉在冒泡",也就是當一個 event 發生時,背後執行的步驟如下:

  1. 會先從 window 開始往下一路執行有註冊的 capture event handler
  2. 到達發生事件的 element 時,再往上一路執行有註冊的 bubble event handler 直到 window

所以 parent 是被 child 的 bubble phase 觸發的,這個 event.target 自然也就落到了 child 上,這也驗證了開頭問題的解答,其實更完整的答案應該是

不使用 arrow function,而使用一般 function 之下時:

  • this 永遠會指向註冊了這個 event handler function 的 element。
  • event.target 指向的是觸發這次 event 事件流的那個 element。
  • 執行的時機,是看這次 event 事件流屬於冒泡還是捕捉。

Event Delegation

透過前面的問題 & 釐清,了解到 event 的傳播是沿著 DOM 的父子層依照樹狀傳遞的,基於這個特性 & event.target 的指向性,我們可以利用它來做 "事件委託 (Delegation)",減少綁定 event handler 的記憶體消耗,看個例子

假設我們有個 table,需求是當某個欄位被點擊到時,該欄位背景色 highlight 成紅色,若直覺去寫可能會寫出下面的樣子

這樣做雖然也可以滿足需求,但很明顯這作法會隨著欄位越多,在記憶體內存有越多重複邏輯的 handler function, 一旦量大將導致效能問題,這時候就可以把 event handler 委託給 td 的父層 table 來處理,如下:

可以看到一樣滿足了欄位背景 highlight 成紅色的需求,但我們並沒有一直在記憶體存入相同邏輯的 function,作法不但更優雅也更省記憶體,唯獨一個小地方要注意的就是,要做 Event Delegation 的父子層 element 不要隔太多層級,不然有可能會沒注意到去觸發其他中間層的 event handler 喔。

--

--

Huge Gun

槍再大把,沒子彈是不行的;通過學習,鍛造自己的子彈!https://github.com/HsienW