天天看點

面試官:說說哪些浏覽器事件不會冒泡

你知道哪些浏覽器事件不會冒泡嗎?

回答這個問題之前,我們首先要具備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​

​必須在捕獲階段才能完成事件委托。

注意:有個類似滾動事件的叫滾輪事件​

​wheel​

​​是可以觸發冒泡的( MDN - wheel_event ​),我們甚至可以通過額外注冊 ​

​wheel​

​​ 監聽事件并阻止其冒泡進而讓 ​

​scroll​

​​ 事件失效,不過隻要滾動條還在 ​

​scroll​

​​ 還是可以不通過滾輪來控制滾動的,是以還記得前面我們怎麼讓元素滾動起來的嗎?就是設定了 ​

​overflow: scroll;​

​,是以控制滾動應該使用 CSS 而不是 JS 事件。

​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​

​ 就不會出現以上這些問題了。

面試官:說說哪些浏覽器事件不會冒泡

Media

總結

繼續閱讀