谈谈JS事件冒泡和事件捕获

  前言

 JavaScript 与 HTML 的交互是通过事件实现的。

 而事件流描述了页面接收事件的顺序。DOM2 Event 规范规定事件流分为3个阶段:事件捕获、到达目标和事件冒泡,如下图。非常有意思的是 IE 和 Netscape(网景) 开发团队提出了几乎完全相反的事件流方案。IE 支持事件冒泡流,而 Netscape 将支持事件捕获流。后来 w3c 采用折中的方式,制定了统一的标准——先捕获再冒泡。

    

一、事件冒泡

  事件冒泡可以形象地比喻为把一颗石头投入水中,泡泡会一直从水底冒出水面。也就是说,事件会从最内层的元素开始发生,一直向上传播,直到到根结点。

  接下来我们通过一个简单的案例来说明事件冒泡:

<body>

<div id="div1">
    div1
    <div id="div2">
        div2
        <div id="div3">这是div3</div>
    </div>
</div>

<script>
    let div1 = document.getElementById('div1');
    let div2 = document.getElementById('div2');
    let div3 = document.getElementById('div3');
    div1.addEventListener('click',function(){
        console.log("这是div1的点击事件");
    },false);
    div2.addEventListener('click',function(){
        console.log("这是div2的点击事件");
    },false);
    div3.addEventListener('click',function(){
        console.log("这是div3的点击事件");
    },false);
</script>

</body>
addEventListener(event, function, useCapture)方法用于向指定元素添加事件 

  第一个参数是需要绑定的事件
  第二个参数是触发事件后要执行的函数
  第三个参数默认值是false,表示在事件冒泡阶段调用事件处理函数;如果参数为true,则表示在事件捕获阶段调用处理函数。(可不选)

  当我们只点击 div3 时,控制台出现如下结果:

    

  

  这里我们要注意,我们传递的仅仅是事件触发,也就是说当点击div3仅仅触发了父级的点击事件,并没有把自己的绑定的函数给父级,父级的执行情况,取决于自己所绑定的函数。在有些时候事件冒泡也会给我们带来困扰,例如在我们点击div3时,我们不希望div1和div2触发事件。这有什么办法解决吗?

  •  方法:在相应的处理函数内,加入  event.stopPropagation(),终止气泡往上冒,这样事件停留在本节点,不会再往外传播了。
<script>
    let div1 = document.getElementById('div1');
    let div2 = document.getElementById('div2');
    let div3 = document.getElementById('div3');
    div1.addEventListener('click',function(){
        console.log("这是div1的点击事件");
        event.stopPropagation();
    },false);
    div2.addEventListener('click',function(){
        console.log("这是div2的点击事件");
        event.stopPropagation();
    },false);
    div3.addEventListener('click',function(){
        console.log("这是div3的点击事件");
        event.stopPropagation();
    },false);
</script>

 

 点击div3后不会出现冒泡

   其实事件冒泡不仅会给我们带来困扰,还会给我们带来优点,那就是事件委托,关于事件委托的内容会在下一篇详细介绍。

 

二、事件捕获 

  与事件冒泡相反,事件会从最外层开始发生,直到最具体的元素。

  将上述事件冒泡代码中的false全都改为true变成变成事件捕获阶段调用函数,再次点击div3会出现如下情况:

  

  可以看出和冒泡事件正好相反,那么它两谁的优先级高呢?让我们把div1改为true变成事件捕获再次点击div3来试一试:

  

   可以看出div1先执行了,由此可以得出:事件捕获优先于事件冒泡。

 

  补充

 并不是所有的事件都会产生冒泡,例如以下事件就不会产生冒泡:

 焦点事件

  • blur(当一个元素失去焦点的时候被触发。它和 focusout 事件的主要区别是 focusout 支持冒泡。)
  • focus  (当一个元素获取焦点的时候被触发)

 UI事件

  • load
  • unload
  • scroll (滚动窗口被触发)

 鼠标事件

  • mouseenter
  • mouseleave

 

posted @ 2021-10-26 21:09  打遍天下吴敌手  阅读(373)  评论(0编辑  收藏  举报