事件处理是创建交互式用户界面的关键部分,浏览器通过事件系统让我们能够捕获和响应用户的输入,比如点击、鼠标移动、键盘输入等。

嵌套元素的“事件”冒泡?!——WEB开发系列52_JavaScript

什么是事件冒泡?

事件冒泡是指在嵌套的 HTML 元素中,一个事件从最具体的元素开始,然后向上传播到更高层级的父元素。

例如,如果用户点击一个嵌套的按钮,事件首先会被按钮捕获,然后会冒泡到按钮的父元素,接着是父元素的父元素,直到到达 <body> 元素或文档的根元素。这种机制使得一个事件可以被多个元素处理,而不需要为每一个元素单独设置事件监听器。


事件冒泡

让我们先看一个关于事件冒泡的基本示例。在按钮及其父元素上设置点击事件监听器。

HTML 代码

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>事件冒泡示例</title>
    <style>
        div {
            border: 2px solid blue;
            padding: 20px;
            margin: 10px;
        }
        button {
            padding: 10px;
        }
    </style>
</head>
<body>
    <div id="parent">
        <button id="child">点击我</button>
    </div>

    <script src="script.js"></script>
</body>
</html>

JavaScript 代码

document.getElementById("parent").addEventListener("click", function(event) {
    alert("父元素被点击");
});

document.getElementById("child").addEventListener("click", function(event) {
    alert("子元素被点击");
});

嵌套元素的“事件”冒泡?!——WEB开发系列52_嵌套_02

有一个包含按钮的 div 元素,为父元素(div)和子元素(按钮)设置点击事件监听器。

  • 当用户点击按钮时,首先触发按钮的点击事件,然后事件冒泡到父元素 div
  • 结果是用户将看到两个弹窗,依次表示“子元素被点击”和“父元素被点击”。

冒泡顺序

  1. 点击按钮,触发 按钮点击事件
  2. 然后,事件冒泡到父 div,触发 父元素点击事件

如果我们想要控制这一流程,可以使用 stopPropagation() 方法。


使用 stopPropagation() 修复问题

stopPropagation() 方法可以用来阻止事件向上传播。如果在子元素的事件处理函数中调用了 event.stopPropagation(),事件不会冒泡到父元素。

更新后的 JavaScript 代码

document.getElementById("parent").addEventListener("click", function(event) {
    alert("父元素被点击");
});

document.getElementById("child").addEventListener("click", function(event) {
    alert("子元素被点击");
    event.stopPropagation(); // 阻止事件冒泡
});

在这个更新后的代码中,点击按钮时用户只会看到“子元素被点击”,而不会看到“父元素被点击”的弹窗。因为我们在按钮的事件处理函数中调用了 event.stopPropagation(),这使得事件不会继续向上冒泡。


事件捕获

事件捕获是事件处理的另一种机制,与事件冒泡相反。当我们为事件设置监听器时,可以指定事件捕获阶段。在捕获阶段,事件从文档的根元素开始,然后向下传播到最具体的元素。

设置捕获监听器

在添加事件监听器时,可以将第三个参数设置为 true 来启用捕获。

更新后的 JavaScript 代码

document.getElementById("parent").addEventListener("click", function(event) {
    alert("父元素被点击");
}, true); // 启用捕获

document.getElementById("child").addEventListener("click", function(event) {
    alert("子元素被点击");
    event.stopPropagation();
}, true); // 启用捕获

点击按钮时,用户会看到“父元素被点击”,然后是“子元素被点击”。因为这里的事件监听器是以捕获模式添加的,父元素的监听器在子元素之前被触发。

事件捕获和冒泡的总结

  • 事件冒泡从具体元素到父元素。
  • 事件捕获从父元素到具体元素。
  • 默认情况下,事件是以冒泡的方式处理的。

事件委托

事件委托是指将事件监听器附加到一个父元素上,而不是每一个子元素上。这种方法特别适用于动态生成的内容,或者当子元素数量较多时。

事件委托的好处

  • 减少内存开销:只需一个事件监听器就可以处理多个元素。
  • 更容易管理:更方便的添加或删除监听器,尤其是动态内容。
  • 适用于动态子元素:即使更多子元素在未来添加,父元素的监听器仍然可以有效工作。
<ul id="list">
    <li>项 1</li>
    <li>项 2</li>
    <li>项 3</li>
</ul>

<script>
    document.getElementById("list").addEventListener("click", function(event) {
        if (event.target.tagName === 'LI') {
            alert("你点击了: " + event.target.textContent);
        }
    });
</script>

中点击事件的监听器附加到 ul 父元素上,而不是每一个 li 子元素。无论用户点击哪个 li,都会触发父元素的事件监听器。判断 event.target.tagName 确保只有 li 元素的点击事件会被响应。

事件冒泡和捕获是浏览器处理事件的重要机制。实际开发中:

  • 事件冒泡可以让我们轻松处理嵌套元素的事件。
  • 通过调用 stopPropagation() 你可以精确地控制事件流。
  • 事件委托允许你高效地管理多个元素,优化事件处理性能。

嵌套元素的“事件”冒泡?!——WEB开发系列52_JavaScript_03

如有表述欠缺之处还请各位佬指正。