你們好,我是秋風。javascript
嗯...我又來了,此次又是在...楠溪和的討論中產生的問題。html
那事情是怎麼樣的呢?前端
最近楠溪在看事件相關的文章,而後就跑來和我討論說如下代碼的執行效果和網上的文章不一致,代碼以下:java
<div>
<button>123</button>
</div>
<script> var btn = document.querySelector('button'); var div = document.querySelector('div'); btn.addEventListener('click', function () { console.log('bubble', 'btn'); }, false); btn.addEventListener('click', function () { console.log('capture', 'btn'); }, true); div.addEventListener('click', function () { console.log('bubble', 'div'); }, false); div.addEventListener('click', function () { console.log('capture', 'div'); }, true); </script>
複製代碼
以上是一段很簡單的事件註冊的代碼,而後咱們點擊 button
。git
先不看結果,思考一下。github
而後咱們來看看結果web
對於絕大多數前端老鳥來講,會脫口而出地說出如下順序。面試
capture div
bubble btn
capture btn
bubble div
複製代碼
可是不論是MDN,仍是網上大多數的教程而言說的都是這個順序。跨域
對於這個現象,我感到很迷惑,我依稀記得,在幾個月前,Chrome 還不是這樣的行爲,盲猜是否是由於 Chrome 版本的問題呢?瀏覽器
以上動圖的 Chrome 版本是 90.0.4430.212
所以我找了個 Chrome 版本爲 84.0.4109.0 進行測試。
果真是版本的問題,可是事情的追蹤依然很難,因爲搜索了規範以及查了谷歌上的一些資料,並無很好地幫助我解決這個疑惑,我不肯定是由於 Chrome 引入的 bug 仍是出現了什麼問題。
所以我就向 chromium 報告了這個問題。
最終在 Chrome 開發人員的幫助下,找到了這兩個討論
在上述 issues 中能夠看到, 原由是在 bugs.webkit.org/show_bug.cg… 中,有人指出,在 webkit 中當前的事件模型,會致使含有 Shadow DOM 的狀況下,子元素的捕獲事件會優先於父元素的捕獲事件觸發。
而在舊模型中,一旦達到 AT_TARGET ,全部註冊的監聽器就將按照順序被觸發,而無論他們是否被標記爲捕獲。因爲 Shadow DOM 會建立多個 targets ,致使了事件執行順序的錯誤。
而上述問題在 Gecko (Mozilla Firefox 的排版引擎)卻運行正常(先捕獲再冒泡)。爲此 whatwg 提出了一個新的模型結構來解決這個問題。
全部的疑問到此都迎刃而解了,到如今爲主咱們梳理一下咱們的問題。
1.按照舊版本事件觸發機制 | |
---|---|
表現 | 目標元素觸發事件順序和註冊事件順序有關 |
2.新的的事件觸發機制 | |
表現 | 目標元素觸發事件順序按照先捕獲再冒泡的順序觸發 |
而這個版本分界線是在 Chrome 89.0.4363.0 和 89.0.4358.0。
而 Chrome 89.0.4363.0 是在 2020-12-22 發佈的,也就是最近幾個月的事情,所以近幾個月若是你的Chrome 更新了就會遇到和我同樣的現象。
在 Chrome 89.0.4363.0 以及以後版本中,目標元素的觸發事件順序再也不按照註冊順序觸發!而是按照先捕獲再冒泡的形式依次執行!
而後咱們再來看看這樣修改會給咱們帶來怎麼樣的影響。
舉個🌰
<div>
<button>123</button>
</div>
<script> var a = []; var btn = document.querySelector('button'); var div = document.querySelector('div'); btn.addEventListener('click', function () { console.log('bubble', 'btn'); a.push(1); }, false); btn.addEventListener('click', function () { console.log('capture', 'btn'); a.push(2); }, true); div.addEventListener('click', function () { console.log('bubble', 'div'); }, false); div.addEventListener('click', function () { console.log('capture', 'div'); }, true); </script>
複製代碼
在新版本中,當 button 元素被點擊後,最終 a 的結果爲 [2,1],而在舊版本中,這個結果則爲 [1,2]。
那對於現階段一些線上代碼改如何改造呢?
那麼如今咱們沒法控制用戶使用哪一個版本的瀏覽器,該如何解決這個問題而來避免遇到線上問題呢?
其實很簡單。
咱們只須要將全部目標元素代碼的順序都按照先書寫捕獲事件代碼,再書寫冒泡事件代碼,就能夠兼容本次的更新。
全部的事情都不是一成不變的,不論是對於一些相對官方的文章或者教程咱們都要抱以懷疑的態度,相信咱們所看到的。也許我這篇的言論在多年以後也會是一個錯誤示例,可是是對當下問題的一個記錄。本文也還有不少不足之處,若是有問題請在評論中指出。
已經向 MDN 提交新的描述,並已經被合入 PR
dom.spec.whatwg.org/#dispatchin…
回看筆者往期高贊文章,也許能收穫更多喔!
2021前端學習路徑書單—自我成長之路:570+
點贊量
教你實現微信8.0『炸裂』的🎉表情特效:400+
點贊量
從破解某設計網站談前端水印(詳細教程):790+
點贊量
從王者榮耀裏我學會的前端新手指引:260+
點贊量
一文帶你層層解鎖「文件下載」的奧祕:140+
點贊量
10種跨域解決方案(附終極大招):940+
點贊量
❤️關注+點贊+收藏+評論+轉發❤️,原創不易,鼓勵筆者創做更好的文章
關注公衆號秋風的筆記
,一個專一於前端面試、工程化、開源的前端公衆號