JS 事件冒泡和事件捕获

发布于2023-08-19 17:54 阅读 166

W3C规定DOM事件流(event flow )存在三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。dom标准事件流的触发的先后顺序为:先捕获再冒泡,即当触发dom事件时,会先进行事件捕获,捕获到事件源之后通过事件传播进行事件冒泡。

1、事件冒泡

     在本示例中,当我们点击孙子div的时候浏览器就会去检查这个div身上没有绑定事件,如果有就执行它;然后再检查它的父元素(儿子div)身上有没有绑定事件,如果有就执行;然后再检查儿子div的父元素身上有没有绑定事件,如果有就执行,依此类推,直到html根元素,这样由内到外的向外触发事件就叫做事件冒泡。


<!DOCTYPE HTML>
<html>
<head>
    <meta charset="utf-8">
    <title>事件冒泡</title>
</head>
<style>
  .parent{
    width: 400px;
    padding: 20px;
    background-color: gray;
  }
  .child{
    padding: 20px;
    background-color: yellow;
  }
  .grandson{
    padding: 20px;
    background-color: green;
  }
</style>
<body>
    <div class="parent">
      爸爸
      <div class="child">
        儿子
          <div class="grandson">孙子</div>
      </div>
    </div>
</body>
</html>
<script>
    let parent = document.querySelector('.parent')
    let child = document.querySelector('.child')
    let grandson = document.querySelector('.grandson')

    parent.addEventListener('click', function (e) {
      console.log('爸爸')
    }) // 注意:这个地方多了一个参数

    child.addEventListener('click', function (e) {
      console.log('儿子')
      // e.stopPropagation() 阻止事件的传播
    }) // 注意:这个地方多了一个参数

    grandson.addEventListener('click', function (e) {
      console.log('孙子')
        // e.stopPropagation() 阻止事件的传播
    }) // 注意:这个地方多了一个参数
</script>

2、事件捕获

     事件捕获刚好和事件冒泡相反,事件触发时是先检查最外层祖先html元素没有绑定事件,如果有则执行它,然后在检查,然后,它移动到<html>中单击元素的下一个祖先元素,并执行相同的操作,然后是单击元素再下一个祖先元素,依此类推,直到到达实际点击的元素,就和剥洋葱一样。



<!DOCTYPE HTML>
<html>
<head>
    <meta charset="utf-8">
    <title>事件捕获</title>
</head>
<style>
  .parent{
    width: 400px;
    padding: 20px;
    background-color: gray;
  }
  .child{
    padding: 20px;
    background-color: yellow;
  }
  .grandson{
    padding: 20px;
    background-color: green;
  }
</style>
<body>
    <div class="parent">
      爸爸
      <div class="child">
        儿子
          <div class="grandson">孙子</div>
      </div>
    </div>
</body>
</html>
<script>
    let parent = document.querySelector('.parent')
    let child = document.querySelector('.child')
    let grandson = document.querySelector('.grandson')

    parent.addEventListener('click', function (e) {
      console.log('爸爸')
    },true) // 注意:这个地方多了一个参数

    child.addEventListener('click', function (e) {
      console.log('儿子')
    },true) // 注意:这个地方多了一个参数

    grandson.addEventListener('click', function (e) {
      console.log('孙子')
    },true) // 注意:这个地方多了一个参数
</script>

3、阻止默认行为:e.preventDefault() 阻止事件传播:e.stopPropagation()


4、事件委托

使用事件委托实现点击点击不同的 li 元素 来获取歌曲的 id



<!DOCTYPE HTML>
<html>
<head>
    <meta charset="utf-8">
    <title>事件委托</title>
</head>
<body>
    <ul class="musiclist">
      <li data-id="1"><span>歌曲1</span><span>作者1</span></li>
      <li data-id="2"><span>歌曲2</span><span>作者2</span></li>
      <li data-id="3"><span>歌曲3</span><span>作者3</span></li>
      <li data-id="4"><span>歌曲4</span><span>作者4</span></li>
      <li data-id="5"><span>歌曲5</span><span>作者5</span></li>
    </ul>
</body>
</html>
<script>
    let musiclist = document.querySelector('.musiclist');
    // 事件处理程序绑定在歌曲列表上面
    musiclist.addEventListener('click', function (e) {
      console.log(e)
      console.log('target', e.target);
      console.log('currentTarget', e.currentTarget);
      let target = e.target;
      if (target.nodeName === 'LI') {
        console.log('当前歌曲ID是' + target.dataset.id)
      }
    })
</script>

微信公众号搜索《每周小知识》每天分享web知识


评论

全部评论

{{item.username}}
{{item.comment_content}}
回复

{{reply.username}} 回复:{{reply.replyname}}

{{reply.content}}

{{reply.isshow ? '取消回复' : '回复'}}

作者

程序员李蛋

一个早早地学会让自己的灵魂充分扩展的人,以后才能将整个世界收入自己的灵魂当中。