深入理解JS中的事件委托

167 阅读4分钟

JavaScript中的事件委托是一种非常有用的事件处理模式,它允许我们利用事件模型的事件冒泡阶段来减少事件处理器的数量,提高网页性能。本文将介绍事件委托的概念、工作原理、优点以及如何在实际项目中应用事件委托。

1、事件模型

事件模型指在Web开发中,处理和管理事件(如用户输入、系统生成的事件等)的机制和流程。在JavaScript中,事件模型非常关键,因为它定义了事件如何创建、传播和被监听器捕获的规则

1.1、事件

在浏览器中,web事件是由 DOM 元素产生的资源,监听事件来实现JS和HTML交互的载体。web事件被定义成了浏览器内置的API。

1.2、事件模型

JavaScript的事件模型包括三个重要的阶段:事件捕获阶段、目标阶段和事件冒泡。这三个阶段也是事件触发的三个阶段:

  1. 事件捕获阶段:指从最外层的元素开始捕获事件,然后逐级向下传递到最具体的元素。这个过程是从DOM树的根节点开始的,逐级向下直到事件的目标元素。事件捕获的目的是在事件到达目标元素之前就能够捕获到它;
  2. 目标阶段:事件到达目标元素本身,触发目标元素上的事件处理程序;
  3. 事件冒泡阶段:事件冒泡正好与事件捕获相反,事件冒泡是指事件从最具体的元素开始发生,然后逐级向上传播到较为不具体的元素(通常是直到文档的根元素)。大多数事件(如点击事件)都会冒泡,这意味着事件不仅仅在其直接绑定的元素上触发,还会在其父元素、祖父元素等上触发。

1.jpg

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="outer">
        <div id="inner">
            <button id="target">点击我</button>
        </div>
    </div>
    <script>
        // addEventListener第三个参数为true时,表示在捕获阶段执行事件处理程序,默认为false,表示在冒泡阶段执行事件处理程序
        document.getElementById('outer').addEventListener('click', function() {
            console.log('outer');
        },true);

        document.getElementById('inner').addEventListener('click', function() {
            console.log('inner');
        });
        document.getElementById('target').addEventListener('click', function() {
            console.log('target');
        });
    </script>
</body>
</html>

点击后,控制台输入如下内容:

2.jpg

2、事件委托

2.1、概念

事件委托是一种在父元素上设置事件监听器来管理多个子元素的事件的技术。这意味着,我们不需要在每个子元素上单独添加事件监听器,而是在其共同的父元素上添加一个事件监听器来处理所有子元素的事件。

2.2、工作原理

事件委托的工作原理基于事件冒泡机制。在DOM中,当一个事件发生在某个元素上时,这个事件不仅仅只在该元素上触发,而是会沿着DOM树向上冒泡,一直传播到根节点。利用这一机制,我们可以在父元素上监听事件,然后根据事件的目标元素(event.target)来判断事件实际是在哪个子元素上触发的。

2.3、优点

  1. 减少内存占用:由于不需要在每个子元素上绑定事件监听,可以显著的减少内存的占用;
  2. 动态元素管理:对于动态添加到页面的元素,不需要单独的去绑定事件程序;
  3. 简化事件管理:简化了事件监听器的管理,使得代码更加简洁易维护。

2.4、举个例子

假设我们有一个任务列表,每个任务项都有一个删除按钮。我们希望点击删除按钮时能删除对应的任务项。使用事件委托,我们可以这样实现:

<ul id="taskList">
    <li>任务1 <button class="deleteBtn">删除</button></li>
    <li>任务2 <button class="deleteBtn">删除</button></li>
    <!-- 更多任务项 -->
  </ul>
  <script>
  
  document.getElementById('taskList').addEventListener('click', function(e) {
    if (e.target && e.target.className === 'deleteBtn') {
      // 删除按钮被点击,移除对应的任务项
      e.target.parentNode.remove();
    }
  });
  </script>

在这个例子中,我们在 #taskList上 设置了一个点击事件监听器,然后检查点击事件的目标元素是否是删除按钮。如果是,就移除对应的任务项。这样,无论我们有多少任务项,都只需要一个事件监听器。

这个绝妙的“事件委托”,也就是react合成事件的重要应用之一。

3、结论

事件委托是一种强大的事件处理模式,它利用了DOM事件冒泡的特性来优化事件监听器的使用,提高网页性能。在处理大量元素的事件时,尤其是在动态内容的情况下,事件委托显得尤为重要。通过合理利用事件委托,我们可以写出更加高效、简洁的JavaScript代码。