首先我們先弄明白瀏覽器事件觸發機制,分為三個階段:
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()
方法,告訴瀏覽器,它默認的動作也不要做了。此事件還是繼續傳播(捕獲、冒泡不會停)