发布于 2026-01-06 1 阅读
0

JavaScript 中的事件冒泡:使用冒泡和捕获高效处理 JavaScript 事件

JavaScript 中的事件冒泡:使用冒泡和捕获高效处理 JavaScript 事件

 

JavaScript 使我们的 Web 应用程序具备交互性。它可以识别用户发起的事件,例如鼠标点击、鼠标滚轮滚动、键盘按键等等。流畅地处理这些用户操作对于提供良好的用户体验至关重要。今天,我们将以鼠标点击事件为例,学习如何高效地处理 JavaScript 事件。

 


addEventListener方法

JavaScript 有一个内置方法,addEventListener可以将其添加到 HTML 节点上。它总共接受 3 个参数,如下所示:

  1. 事件名称。
  2. 当指定事件触发时,用于执行某些代码的回调函数。
  3. 可选参数:捕获的布尔值。(默认设置为 false)。

 

<div id="div1">I am a div1</div>
Enter fullscreen mode Exit fullscreen mode
const div1 = document.getElementById("div1");

div1.addEventListener("click", function() {
  console.log("div1 clicked");
});
Enter fullscreen mode Exit fullscreen mode

正如你所料,点击“我是一个div”文本会在控制台输出“div1被点击”。让我们在HTML中用一个新的div元素包裹这段文本。你能猜到现在点击这段文本会输出什么吗?

<div id="div1">
  <div id="div2">I am a div1</div>
</div>
Enter fullscreen mode Exit fullscreen mode
const div1 = document.getElementById("div1");

div1.addEventListener("click", function() {
  console.log("div1 clicked");
});
Enter fullscreen mode Exit fullscreen mode

即使我们点击了 id 为“div2”的 div,结果仍然保持不变,并打印出“我是 div1”。

 


事件酝酿中

在 JavaScript 中,事件默认会冒泡。事件冒泡是指事件从最内层的 HTML 元素开始,沿着 DOM 层级向上传递,直到到达监听该事件的元素。这种传递过程也常被称为事件传播事件委托

在上面的例子中,点击文本“I am a div1”等同于点击#div2。因为我们在父元素#div1上设置了事件监听器,所以事件会触发最内层的子元素#div2并向上冒泡。

这里还有一个例子。我们再用 JavaScript 给 div2 添加一个事件监听器。

<div id="div1">
  <div id="div2">I am a div</div>
</div>
Enter fullscreen mode Exit fullscreen mode
const div1 = document.getElementById("div1");
const div2 = document.getElementById("div2");

div1.addEventListener("click", function() {
  console.log("div1 clicked");
});
div2.addEventListener("click", function() {
  console.log("div2 clicked");
});
Enter fullscreen mode Exit fullscreen mode

以下是事件冒泡的结果。

div2 clicked
div1 clicked
Enter fullscreen mode Exit fullscreen mode

注意,我们还可以向根级元素(例如 html 和 body)添加事件监听器,事件会一直冒泡到这些元素。以下是事件层级结构:

目标 -> 主体 -> HTML -> 文档 -> 窗口

 


停止传播

有时,你不希望事件沿某个方向传播,这时可以使用stopPropagation()事件对象。事件对象作为参数传递给回调函数。

...

div2.addEventListener("click", function(event) {
  event.stopPropagation();
  console.log("div2 clicked");
});
Enter fullscreen mode Exit fullscreen mode

结果:

div2 clicked
Enter fullscreen mode Exit fullscreen mode

 


事件冒泡的实际应用

假设你正在用纯 JavaScript 开发一个待办事项应用,用户可以点击待办事项来切换其完成状态。为每个待办事项添加单独的事件监听器是不合理的,因为

  1. 列表可能会很长。(这个过程会变得很繁琐。没错,你可以用循环来添加事件监听器,但是应用中事件监听器过多会消耗大量浏览器内存,导致应用运行缓慢。)
  2. 可以动态添加新的待办事项。(无法为其添加事件监听器)

我们可以通过给包含列表的父元素添加事件监听器来解决这个问题。请仔细查看以下代码的作用。

<ul class="list">
    <li class="item">Wash dishes</li>
    <li class="item">Walk your dog</li>
</ul>
Enter fullscreen mode Exit fullscreen mode
.completed {
    text-decoration: line-through;
}
Enter fullscreen mode Exit fullscreen mode
const list = document.querySelector(".list");

list.addEventListener("click", e => {
    e.target.classList.toggle("completed")
})
Enter fullscreen mode Exit fullscreen mode

点击某个元素会切换completed该元素的类,从而为文本添加删除线。同时还会生成一个事件对象,该对象具有一个target属性。该e.target属性指向被点击的 DOM 元素,你可以添加classListtoggle切换该元素的类。

 


目标值与当前目标值

这是一个常见的面试题。你刚刚学到,`target` 指的是触发事件的 DOM 元素。`CurrentTarget` 指的是事件监听器正在监听的 DOM 元素。让我们在函数内部进行控制台e.target输出。e.currentTarget

const list = document.querySelector(".list");

list.addEventListener("click", e => {
    console.log(e.target); // <li class="item completed">Walk your dog</li>
    console.log(e.currentTarget); // <ul class="list"></ul>
    e.target.classList.toggle("completed")
})
Enter fullscreen mode Exit fullscreen mode

如果父元素有事件监听器,但我们阻止了子元素中的事件传播,则 currentTarget 指向阻止传播的 DOM 元素。

 


事件捕获

要启用此功能,请将其true作为第三个参数传递给 addEventListener 方法。

Element.addEventListener("click", function(){}, true);
Enter fullscreen mode Exit fullscreen mode

这种传播方式很少使用。它不是从内到外传播,而是反转方向,从外到内传播。以下是层级结构。

窗口 -> 文档 -> HTML -> 正文 -> 目标

所以,如果你想先获取事件监听的父元素,就可以使用这个方法。我们来看前面一个例子。

<div id="div1">
  <div id="div2">I am a div</div>
</div>
Enter fullscreen mode Exit fullscreen mode
const div1 = document.getElementById("div1");
const div2 = document.getElementById("div2");

div1.addEventListener("click", function() {
  console.log("div1 clicked");
}, true);
div2.addEventListener("click", function() {
  console.log("div2 clicked");
});
Enter fullscreen mode Exit fullscreen mode

结果

div1 clicked
div2 clicked
Enter fullscreen mode Exit fullscreen mode

 


概括

认真倾听用户交互并正确处理是打造无 bug 应用的第一步。记住,冒泡机制就像气泡一样,从内部向上冒泡到外部;而捕获机制则是事件从内部向下冒泡的过程!感谢阅读!

 

文章来源:https://dev.to/shimphillip/handing-javascript-events-efficiently-with-bubble-and-capture-4ha5