跳到主要内容位置

JavaScript事件冒泡机制

一个问题

如果有下面一段代码:

  1. 在 HTML 中,定义了嵌套的 3 个 <div/>,ID 分别为 div1、div2、div3。
  2. 在 JavaScript 中定义一个点击事件处理函数,打印当前执行事件元素的 id。
  3. 把事件处理函数分别注册到这 3 个 div 中。

这个时候,如果点击最里边的 div3 元素,你猜代码的输出结果是什么?

// html:
<div id="div1">
div1
<div id="div2">
div2
<div id="div3">div3</div>
</div>
</div>;

// javascript:

function handleClick(event) {
console.log(event.currentTarget.id);
}
for (let i = 1; i <= 3; i++) {
let div = document.getElementById(`div${i}`);
div.addEventListener("click", handleClick);
}
选项
A.div3
B.div3, div2, div1

答案是:B。 为什么结果会是这样呢?这得从 JavaScript 的事件冒泡机制说起。

什么是事件冒泡机制

事件冒泡机制是说,在给某个 DOM 元素设置了事件监听器之后,例如鼠标点击事件,在触发事件时,浏览器不仅仅执行该元素的事件处理函数,还会顺着 DOM 树的结构,一级一级的往上查找,是不是有父级元素注册了相同的事件监听器,如果有的话,还会执行父级元素的事件处理函数,直到 <html /> 根元素为止。

在上边的例子中,点击了 div3 元素之后:

  • 先执行了 div3 的点击事件处理函数,此时 event.currentTarget 是 div3 这个元素,打印出它的 id 为 div3。
  • 接着浏览器会查找上级元素 div2 有没有点击事件监听,结果有,那么就执行了它的处理函数打印出 div2。
  • 同理,打印出最外层的 div1 之后,就再没有点击事件监听了,这个时候事件才停止冒泡了。

阻止事件冒泡机制

事件冒泡机制会给开发中带来意想不到的结果,要阻止它也很简单,只需要在事件处理函数中,调用事件参数的 stopPropagation() 方法,这样事件在当前元素处理完成之后就结束了,不会再查找父级组件相同的事件监听了。

event.stopPropagation();

如果我们在之前的例子中,事件处理函数里,加上这段代码,那么,再点击最里边的 div3,就只会打印出 div3 了:

function handleClick(event) {
event.stopPropagation();
console.log(event.currentTarget.id);
}

对于一些老的浏览器,例如 IE9 以下,如果要阻止事件冒泡,需要设置 event 参数的 cancelBubble 属性为 true:

event.cancelBubble = true;

这样也就阻止事件冒泡了。如果以后遇到了同时触发了多个事件的情况,可以先想一下是不是事件冒泡机制捣的鬼,如果是就把它停止。

总结

好了,这个就是 JavaScript 事件冒泡机制,你学会了吗?如果有帮助请三连,想学更多有用的前端开发知识,请关注峰华前端工程师,感谢观看!