[DOM] Event Propagation I : 事件捕捉和冒泡-Event Capture & Bubble

Huge Gun
4 min readMay 2, 2020

--

這篇是個人的筆記之一,也希望對他人了解 Javascript Event 捕捉跟冒泡這塊有些幫助,其實它也與常用到的 addEventListener & preventDefault & stopPropagation 息息相關本篇後面都會提到,若有不對的地方也能和我說喔!

Event Capture & Bubble

先說說 Capture (捕捉) 與 Bubble (冒泡),要看清楚兩著的差異,最直接的方法就是圖解,直接上圖吧!

Source: Event Flow: capture, target, and bubbling

Capture Phase:

DOM 傳遞順序是由上到下(從 window 到 document 一路下傳到被點擊的 div)

Bubble Phase:

DOM 傳遞順序是由下到上(從被點擊的 div 往上傳到 document 再到 window)

假設我們對一個 DOM (某 button or 任何 node) 添加一個 click event,並點擊它後產生的傳遞順序,是捕捉還是冒泡呢?

答案是: “先捕捉再冒泡”

什麼原因造成的呢? 要從歷史來說,會產生兩種不同的傳遞順序,是因為當年瀏覽器角逐時期,Microsoft & Netscape 兩巨頭分別提出的兩種不同事件流處理法,而最後 W3C 做的決定是兩種都支援,並把兩種合在一起,才導致現在的瀏覽器同時存在這兩種方式,目前把先捕捉再冒泡當成 “預設”,所以假設當一個 event 發生時,會產生的傳遞順序如下圖 :

Source: DOM event propagation basics

這也應證了上面的答案: "先捕捉再冒泡";然而我們前面說到是 "預設" 的情況下,也就是說這個傳遞順序是可以改變的,接著透過前述說到的addEventListener & stopPropagation &preventDefault 來看看吧!

addEventListener

它在做什麼大家都很熟了,不再贅述,如果還不了解的小夥伴可以參考[MDN-addEventListener],接著我們將聚焦它的第三個參數上

target.addEventListener(type, listener, options); // 第三個是 Boolean 

當 options 參數設定的 Boolean 值不同時,它對傳遞順序的改變,如下:

True: 把這個 listener 添加到捕獲階段 (Capture)。

False: 把這個 listener 添加到冒泡階段 (Bubble)。

沒給: 使用預設,把這個 listener 添加到冒泡階段 (Bubble)。

弄清楚了 Event Capture & Bubble 的傳遞順序以及特性之後,我們常見的一個問題就是當綁定了 addEventListener DOM 的父層,有相同的綁定事件時會因為冒泡的關係一同被觸發,如下:

當查看 console 時會發現,明明只按了 child 卻連 parent 一起被觸發

Click demo

這很顯然不是我們要的,後面來說說怎麼避免

stopPropagation & preventDefault

我們想要阻擋冒泡亂觸發父層事件,那麼就可以利用 event object 提供的 stopPropagation,輕鬆解決

上述例子還有一個小問題,就是都是只用 div,那如果是用 from、a 等等 html 元素,他們本身就已經有預設行為,那當想修改時該怎麼做呢? 這時就可以用 event 給的 preventDefault,來中止預設行為

但要注意的是, preventDefault 雖然會中止預設行為,但並不會阻止事件冒泡!!! 所以要停止冒泡還是要用 stopPropagation 喔!

--

--

Huge Gun

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