JavaScript里的事件冒泡

661 阅读3分钟

「这是我参与11月更文挑战的第24天,活动详情查看:2021最后一次更文挑战

冒泡

让我们先来看一个简单的示例:

以下代码中,我们在div上加了一个onclick事件,但是如果我们点击div里面的p标签,会发现,这个事件也被执行了,这是为什么呢?

image-20211125233815238

其实这就是所谓的事件冒泡冒泡(bubbling)原理很简单:

当一个事件发生在一个元素上,它会首先运行在该元素上的处理程序,然后运行其父元素上的处理程序,然后一直向上到其他祖先上的处理程序。

可以想象把一颗石头投入水中,泡泡会一直从水底冒出水面。也就是说,事件会从最内层的元素开始发生,一直向上传播,直到document对象。

💥 注意:这里传递的仅仅是事件,并不传递所绑定的事件函数。所以如果父级没有绑定事件函数,就算传递了事件,也不会有什么表现,但事件确实传递了。

假如现在又一个3层的嵌套FORM > DIV > P,它们各自拥有一个处理程序:

<form onclick="alert('form')">FORM
  <div onclick="alert('div')">DIV
    <p onclick="alert('p')">P</p>
  </div>
</form>

点击内部的 <p> 会首先运行 onclick

  1. 在该 <p> 上的。
  2. 然后是外部 <div> 上的。
  3. 然后是外部 <form> 上的。
  4. 以此类推,直到最后的 document 对象。

如果此时你

  • 点击p标签,将会弹出3个alert,顺序为pdivform
  • 点击div标签,将会弹出2个alert,顺序为 divform
  • 点击form标签,只会弹出1个form

event.target

之前有说过,当事件发生时,浏览器会创建一个 event 对象,将详细信息放入其中,并将其作为参数传递给处理程序。其中的

event.target可以准确地获取事件源(指的是真正触发事件的那个元素)

event.currentTarget指绑定了事件监听的元素(触发事件元素的父级元素)

如开头的这个示例:

如果点击了p标签,则event.target获取到的是p标签,而event.currentTarget获取到的则是绑定了事件的div标签。

image-20211126002516029

💥注意:如果直接打印event,展开这个对象会发现currentTarget的值为null,但是如果是直接打印event.currentTarget,可以获取到具体的值。(currentTarget 在你控制台展开查看的时候,已经不存在了。你要是想拿到它,需要赋值给一个值,然后再进行操作。)
👉 Stack Overflow相关问题回答
👉 github上的相关问题回答

停止冒泡

取消事件冒泡有两种方式:

  • 标准的W3C 方式:e.stopPropagation(); 这里的stopPropagation是标准的事件对象的一个方法,调用即可

  • 非标准的IE方式:ev.cancelBubble=true; 这里的cancelBubble是 IE事件对象的属性,设为true即可

阻止冒泡的函数封装

function stopBubble(e) {
    //如果提供了事件对象,则这是一个非IE浏览器
   if ( e && e.stopPropagation ){
      //因此它支持W3C的stopPropagation()方法
      e.stopPropagation();
   }else{
      //否则,我们需要使用IE的方式来取消事件冒泡
      window.event.cancelBubble = true;
   } 
}

如果一个元素在一个事件上有多个处理程序,即使其中一个停止冒泡,其他处理程序仍会执行。换句话说,event.stopPropagation() 停止向上移动,但是当前元素上的其他处理程序都会继续运行。

有一个 event.stopImmediatePropagation() 方法,可以用于停止冒泡,并阻止当前元素上的处理程序运行。使用该方法之后,其他处理程序就不会被执行。

参考资料:

Bubbling and capturing


🎨【点赞】【关注】不迷路,更多前端干货等你解锁

往期推荐

👉 一起来看看JS的原型继承

👉 JS中的getter和setter你会用吗?

👉 深入理解ES6箭头对象

👉 JS的装饰器模式实例分析