你知道哪些浏覽器事件不會冒泡嗎?
回答這個問題之前,我們首先要具備DOM事件流捕獲與冒泡的知識,這裡隻講JS中如何設定這兩種事件監聽,例如對body注冊點選事件:
document.body.addEventListener('click', e {
console.log('觸發捕獲階段');
}, true)
document.body.addEventListener('click', e {
console.log('觸發冒泡階段');
}, false)
具體差別在第三個參數,w3c規定了表示捕獲階段觸發,
true
表示冒泡階段觸發,預設
false
。
false
在JS中通常利用冒泡來進行事件委托,但并不是所有事件都會冒泡。下面我們看看哪些事件是不能冒泡的,又有哪些相關應用場景。
scroll、focus、blur、resize
假設有如下一段html結構
<ul id="container">
<ul id="outer">
<div id="inner"></div>
</ul>
</ul>
我們隻需設定
overflow: scroll;
,當内層長度超出外層時元素就會出現滾動條,此時應有兩個滾動事件,我們分别為
container
和
outer
添加
scroll
監聽:
document.getElementById('container').addEventListener('scroll',
function (e) {
console.log('container scroll')
},
);
document.getElementById('outer').addEventListener('scroll',
function (e) {
console.log('outer scroll')
},
);
此時滾動内層,我們看到并不會觸發外層的事件監聽:

而如果設定成捕獲監聽呢?
document.getElementById('container').addEventListener('scroll',
function (e) {
console.log('container scroll')
},
true
);
document.getElementById('outer').addEventListener('scroll',
function (e) {
console.log('outer scroll')
},
true
通過這個例子我們可以得出結論,
scroll
無法觸發冒泡,而捕獲事件可以正常觸發,是以
scroll
必須在捕獲階段才能完成事件委托。
注意:有個類似滾動事件的叫滾輪事件是可以觸發冒泡的( MDN - wheel_event ),我們甚至可以通過額外注冊
wheel
監聽事件并阻止其冒泡進而讓
wheel
事件失效,不過隻要滾動條還在
scroll
還是可以不通過滾輪來控制滾動的,是以還記得前面我們怎麼讓元素滾動起來的嗎?就是設定了
scroll
,是以控制滾動應該使用 CSS 而不是 JS 事件。
overflow: scroll;
focus
、
blur
、
resize
這幾個事件和
scroll
道理是一樣的,都不會觸發冒泡,是以事件也都不能通過阻止冒泡取消,它們了解起來比較直覺,就不多做闡述了。
mouseenter、mouseleave
mouseover
&
mouseenter
均為滑鼠移動到元素上的事件,兩者差別在于後者不會冒泡。
<ul id="outer">
<li id="inner"></li>
</ul>
假設給
ul
設定了
mouseover
事件,在滑鼠經過
ul
時因為
ul
中還有
li
元素,滑鼠每經過一個
li
元素就會冒泡到
ul
上的
mouseover
,造成多次觸發:
document.getElementById('outer').addEventListener('mouseover',
function() {console.log('滑鼠進入了外層');}
);
document.getElementById('inner').addEventListener('mouseover',
function() {console.log('滑鼠進入了内層');}
);
這時就需要在内層額外阻止冒泡(
e.stopPropagation()
)才能解決多次觸發的問題,不過滑鼠從
li
移出到
ul
上還是觸發了
ul
的監聽事件,其實這并不符合常理,因為此時滑鼠還是在
ul
内的。相比之下直接使用
mouseenter
就不會出現以上這些問題了。