你们好,我是秋风。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+
点赞量
❤️关注+点赞+收藏+评论+转发❤️,原创不易,鼓励笔者创做更好的文章
关注公众号秋风的笔记
,一个专一于前端面试、工程化、开源的前端公众号