首先我們先弄明白瀏覽器事件觸發機制,分為三個階段:
1. 事件捕獲階段:window 往事件觸發處傳播,遇到注冊的捕獲事件會觸發 (addEventListener 的 true)
2. 事件目標處理函數:傳播到事件觸發處時觸發注冊的事件 (博主沒搞懂這個階段)
3. 事件冒泡階段:從事件觸發處往 window 傳播,遇到注冊的冒泡事件會觸發(addEventListener 的 false 和 onclick、onmouseover...)
dom.addEventListener('click', function(ev) {
// do something
}, false)
dom.addEventListener('click', function(ev) {
// do something
}, {
useCapture: false, // 是否在捕獲階段觸發
once: false, // 是否只觸發一次,如果 true ,則觸發后馬上銷毀
passive: false, // 如果是true,則調用 ev.preventDefault 會被忽略
})
事件觸發順序:
如果觸發的 ev.target 直接是 dom 本身,那么執行順序不按 useCapture 來,因為這些事件會同時觸發,這個時候觸發順序是按注冊順序來。
如果觸發的 ev.target 是 dom 的某個子節點,那么執行順序按 useCaputrue 來,先 addEventlistener true,然后 onClick 和 addEventListener false 按注冊順序執行。
ev.stopPropagation 和 ev.stopImmediatePropagation
都是阻止捕獲和冒泡階段中當前事件的進一步傳播。
唯一區別是 stopImmediatePropagation 阻止剩下的等效階段的事件,而 stopPropagation 只會阻止往后階段的時間傳播
例如:
let div = document.querySelector('#logo')
div.addEventListener(
'click',
ev => {
console.log('div a')
},
false
)
div.onclick = function(ev) {
console.log('div click')
}
div.addEventListener(
'click',
ev => {
console.log('div b')
// ev.stopPropagation()
// ev.stopImmediatePropagation()
},
true
)
div.addEventListener(
'click',
ev => {
console.log('div b2')
},
true
)
點擊div的一個子元素:
1. 依次打印 div b、div b2、div a、div click
2. 取消注釋 ev.stopPropagation(),依次打印 div b、div b2
2. 取消注釋 ev.stopImmediatePropagation(),打印 div b
preventDefault()方法,告訴瀏覽器,它默認的動作也不要做了。此事件還是繼續傳播(捕獲、冒泡不會停)
