回想起自己學習事件模式那會兒,怎麼都記不住事件的傳播流程和 addEventListener 的設定細節,後來發現好的圖片更能能幫助我們理解邏,所以做了一個 GIF。
事件傳播模式
假設我們現在有三個DOM
節點,並且假設 div 為根節點。(通常事件的捕獲會從根節點開始)
然後我們為這些DOM
節點設定好監聽。
// 設定第三個引數為 true 則在捕獲階段觸發
div.addEventListener('click', null, true);
p.addEventListener('click', null, true);
span.addEventListener('click', null, true);
span.addEventListener('click', null);
p.addEventListener('click', null);
div.addEventListener('click', null);
複製程式碼
現在我們點選span
,那麼click
事件會被觸發,事件會從div
進入捕獲階段,從父級向子級傳遞,到達事件目標後進入冒泡階段,從子級像父級傳遞。
(click)span => div -> p -> span -> span -> p -> div
如果我們點選p
,那麼事件目標為p
元素,事件從div
元素開始捕獲,並從p
元素處折返變為冒泡。
(click)p => div -> p -> p -> div
多次繫結
如果在一個節點上多次繫結同一個事件的監聽,它們會按照事件傳播流程進行(先捕獲後冒泡),如果所處流程一樣則按照先繫結先觸發的原則。
// 設定第三個引數為 true 則在捕獲階段觸發
div.addEventListener('click', null, true) // #1
div.addEventListener('click', null) // #2
div.addEventListener('click', null, true) // #3
p.addEventListener('click', null, true);
p.addEventListener('click', null);
複製程式碼
(click)p => div#1 -> div#3 -> p -> p -> div#2
雖然申明的順序是div#1
div#2
div#3
,但是捕獲先於冒泡,所以 div#1
div#3
依次觸發,而div#2
在冒泡過程中觸發。
stopPropagation
這是Event
物件的一個方法,用來阻止事件進一步傳播。
// 設定第三個引數為 true 則在捕獲階段觸發
// #1
div.addEventListener('click', function (event) {
event.stopPropagation();
}, true)
div.addEventListener('click', null) // #2
div.addEventListener('click', null, true) // #3
p.addEventListener('click', null, true);
p.addEventListener('click', null);
複製程式碼
(click)p => div#1 -> div#3
使用了stopPropagation()
之後,事件就不能進一步傳播了,即使是在div
上,捕獲和冒泡被認為是兩個步驟,所以在捕獲階段傳播被阻止時同節點上的冒泡也不會觸發。
stopImmediatePropagation
這是Event
物件的一個方法,一旦呼叫這個方法,則該元素上未觸發的監聽都不會被觸發,事件也不會進一步傳播。
現在我們在div
上再多增加一個事件監聽,並把stopImmediatePropagation
新增在捕獲事件中第二個觸發的監聽上。
// 設定第三個引數為 true 則在捕獲階段觸發
div.addEventListener('click', null, true) // #1
div.addEventListener('click', null) // #2
// #3
div.addEventListener('click', function (e) {
e. stopImmediatePropagation();
}, true)
div.addEventListener('click', null, true) // #4
p.addEventListener('click', null, true);
p.addEventListener('click', null);
複製程式碼
(click)p => div#1 -> div#3
使用了stopImmediatePropagation()
之後,連當前節點中等待觸發的監聽都沉默了。
擴充套件閱讀
在比較新的瀏覽器中,addEventListener
支援更多引數配置,第三個引數型別支援object
。
target.addEventListener(type, listener[, options]);
這個 options 支援三個欄位
- capture
Boolean
是否在捕獲模式觸發 - once
Boolean
是否僅觸發一次 - passive
Boolean
是否使用被動模式
這裡展示一下once
的效果
// 設定第三個引數為 true 則在捕獲階段觸發
div.addEventListener('click', null, true);
p.addEventListener('click', null, true);
span.addEventListener('click', null, true);
span.addEventListener('click', null);
p.addEventListener('click', null, {once: true}); // 在冒泡階段只觸發一次
div.addEventListener('click', null);
複製程式碼
(click)span => div -> p -> span -> span -> p -> div
(click)span => div -> p -> span -> span -> div
Demo
羅小黑寫寫文字
如果喜歡文章 請留下一個贊~ 如果喜歡文章 分享給更多人~
自由轉載-非商用-非衍生-保持署名(創意共享3.0許可證) 轉載時請保留原文連結 以保證可及時獲取對文章的訂正和修改