事件捕捉 & 事件冒泡 (Event capturing & event bubbling)
事件捕捉 (Event capturing)
事件傳遞的順序是從上到下,由最外層的Window到Document最後到事件發起的Element。
graph TD
window["Window"] --- document["Document"]
window["Window"] -.-> document["Document"]
document --- html["Element html"]
document -.-> html["Element html"]
html --- body["Element body"]
html -.-> body["Element body"]
body --- div["Element div"]
body -.-> div["Element div"]
事件冒泡 (Event bubbling)
而事件冒泡(Event bubbling)則是相反,事件傳遞的順序是從下到上,由事件發起的Element到Document最後再到Window。
graph TD
window["Window"] --- document["Document"]
document["Document"] -.-> window["Window"]
document --- html["Element html"]
html["Element html"] -.-> document
html --- body["Element body"]
body["Element body"] -.-> html
body --- div["Element div"]
div["Element div"] -.-> body
事件傳遞順序
把以上兩種機制合在一起看的話,事件傳遞的順序就會是由上而下再由下而上, 也就是說先捕捉後冒泡:
而這是因為當年兩大龍頭 Microsoft 跟 Netscape 分別提出了不同的處理順序,最後 W3C 決定把兩種機制合在一起同時支援並且把
先捕捉後冒泡設定為預設行為。因此當一個事件發生時,他的傳遞順序會是如圖:
graph TD
window["Window"] -- 1. capture --> document["Document"]
document["Document"] -. 8. bubble .-> window["Window"]
document -- 2. capture --> html["Element html"]
html["Element html"] -. 7. bubble .-> document
html -- 3. capture --> body["Element body"]
body["Element body"] -. 6. bubble .-> html
body -- 4. capture --> div["Element div"]
div["Element div"] -. 5. bubble .-> body
同樣我們也可以從事件傳遞的階段常數(Event Phase)了解到他的順序:
| 常數 | 值 |
|---|---|
| none | 0 |
| capturing | 1 |
| at target | 2 |
| bubbling | 3 |
EventTarget.addEventListener()
target.addEventListener(type, listener, useCapture)
addEventListener是大家很常使用的一個api, 但是我們很少會注意到第三個參數上:
useCapture (optional): boolean, default是false,用來指定這個event是使用捕捉(capturing)還是冒泡(bubbling)
事件冒泡 (useCapture: false, Event bubbling)
在這個範例中,我們使用useCapture的default value,試著點擊Layer可以看到event是使用 冒泡(bubbling)機制:
事件捕捉 (useCapture: true, Event capturing)
而以下的範例是使用useCapture: true,試著點擊Layer可以看到event是使用 捕捉(capturing)機制:
Event.stopPropagation()
然而在實際的情況下,我們不一定會希望事件一層一層地被傳遞,這時候我們可以使用Event.stopPropagation()來阻止當前事件繼續進行捕捉或冒泡。
舉個例子來說,我們有一個button他的上面還有另一個 Element用來控制value是asc還是desc。我們預期的結果是點擊sort type的時候,他會切換成asc或desc但不會觸發button的event,只有在點擊button的時候才會觸發button上的event: