Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Day385:在一个 DOM 上同时绑定两个点击事件:一个用捕获,一个用冒泡。事件会执行几次?先执行冒泡还是捕获? #1220

Open
Genzhen opened this issue Sep 10, 2021 · 9 comments
Labels
JavaScript teach_tag

Comments

@Genzhen
Copy link
Collaborator

Genzhen commented Sep 10, 2021

每日一题会在下午四点在交流群集中讨论,五点小程序中更新答案
欢迎大家在下方发表自己的优质见解

二维码加载失败可点击 小程序二维码

扫描下方二维码,收藏关注,及时获取答案以及详细解析,同时可解锁800+道前端面试题。


参考分析

冒泡是从下向上,DOM 元素绑定的事件被触发时,此时该元素为目标元素,目标元素执行后,它的祖先元素绑定的事件会向上顺序执行。

addEventListener 函数的第三个参数设置为 false,说明不为捕获事件,即为冒泡事件。

捕获则和冒泡相反,目标元素被触发后,会动目标元素的最顶层祖先元素往下执行到目标元素为止。

当一个元素绑定了两个事件,一个是冒泡,一个是捕获。

首先需要明确的是,绑定了几个事件就会执行几次。

对于执行顺序的问题需要注意一下。该 DOM 上的事件如果被触发,会有这几种情况。

  • 如果该 DOM 是目标元素,则按事件绑定顺序执行,不区分冒泡/捕获
  • 如果该 DOM 是处于事件流中的非目标元素,则先执行捕获,后执行冒泡

因为 W3C 标准有说明,先发生捕获事件,后发生冒泡事件。所有事件的顺序是:其它元素捕获阶段事件-> 本元素代码书序事件 ->其它元素冒泡阶段事件

另外需要注意的是,在冒泡阶段,向上执行的过程中,已经执行过的捕获事件不再执行,只执行冒泡事件。

@Genzhen Genzhen added the JavaScript teach_tag label Sep 10, 2021
@longjinxiang
Copy link

如果该 DOM 是目标元素,则按事件绑定顺序执行,不区分冒泡/捕获 <<< 这句话有问题,测试以下代码,都是先执行捕获,再执行冒泡,与事件绑定顺序无关

window.addEventListener('click', () => {console.log('aa')})
window.addEventListener('click', () => {console.log('bbbbbbb')}, true)

@specialgirlgotoheaven
Copy link

chrome,firefox都支持两种事件,捕获和冒泡,IE仅支持冒泡

@Zenquan
Copy link

Zenquan commented Dec 20, 2021

 <div id="btn">点击
    <div id="btn2" style="margin: 100px;">
      点击2
    </div>
  </div>
  <script>
    const btn = document.getElementById('btn')
    const btn2 = document.getElementById('btn')
    btn.addEventListener('click', () => {console.log('aa')})
    btn.addEventListener('click', () => {console.log('bb')}, true)
    
    btn2.addEventListener('click', () => {console.log('cc')})
    btn2.addEventListener('click', () => {console.log('dd')}, true)
  </script>

在chrome的结果都是

"bb"
"dd"
"aa"
"cc"

@QQhuan
Copy link

QQhuan commented Mar 29, 2022

老哥,经过实践,触发目标元素的点击事件,不论绑定捕获冒泡的顺序如何更改,回调的顺序都是先捕获再冒泡!!!火狐谷歌都是...
如果是我理解有误麻烦指正,如果是参考分析有误还请订正。

@bigbigfan
Copy link

公众号好像不维护了。但是还是帮忙留言chrome的实际行为是「该场景下捕获总是在冒泡之前触发」

@whenTheMorningDark
Copy link

如果目标DOM元素有事件,则先事件,后捕获,然后在冒泡。

@YuArtian
Copy link

 <div id="btn">点击
    <div id="btn2" style="margin: 100px;">
      点击2
    </div>
  </div>
  <script>
    const btn = document.getElementById('btn')
    const btn2 = document.getElementById('btn')
    btn.addEventListener('click', () => {console.log('aa')})
    btn.addEventListener('click', () => {console.log('bb')}, true)
    
    btn2.addEventListener('click', () => {console.log('cc')})
    btn2.addEventListener('click', () => {console.log('dd')}, true)
  </script>

在chrome的结果都是

"bb"
"dd"
"aa"
"cc"

哈哈哈哈哈哈哈哈哈

@robert88
Copy link

const btn2 = document.getElementById('btn') 错误了

@houchaowei
Copy link

chrome,firefox都支持两种事件,捕获和冒泡,IE仅支持冒泡

我觉得这个得加上浏览器的兼容性问题,脱离兼容性说这个,有点缺乏完整性,很多回答是ie之外的浏览器,确实是不论绑定的事件的先后顺序,先捕获后冒泡,这个可以结合react中实现的合成事件来说或许更完整些,react的合成事件就是基于兼容性,为了磨平浏览器的差异,实现了一套类似冒泡阶段执行事件的机制,在合成事件中,只在冒泡阶段执行一次。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
JavaScript teach_tag
Projects
None yet
Development

No branches or pull requests

10 participants