编程

事件委派:一项改进 JavaScript 性能的技术

827 2023-11-18 23:07:00

摘要

本文将介绍事件委派是什么,以及它如何通过减少事件监听的数量优化 JavaScript 代码,以及如何用实际示例实现事件委派。

介绍

假设我们有一个拥有多个链接的导航菜单,我们希望在用户点击链接时实现平滑滚动效果。

<nav class="nav">
  <ul class="nav__links">

    <li class="nav__item">
      <a class="nav__link" href="#about">About</a>
    </li>

    <li class="nav__item">
      <a class="nav__link" href="#projects">Projects</a>
    </li>

    <li class="nav__item">
      <a class="nav__link" href="#testimonials">Testimonials</a>
    </li>

  </ul>
</nav>

不好的方式

一种直率的方法是循环所有链接,并为每个链接添加一个点击事件监听器,如下所示:

document.querySelectorAll('.nav__link').forEach(function(el) {
    el.addEventListener('click', function(e) {
        e.preventDefault();

        const id = this.getAttribute('href');

        document.querySelector(id).scrollIntoView({
            behavior: 'smooth'
        });
    });
});

这可以工作,不过有一个问题:我们需要添加根据链接数量添加多个监听器,这将影响网页的性能以及内存使用。假设我们有一百个链接,那将会有许多不必要的事件监听器!

如何解决该问题?答案是事件委派。

好的方式

事件委派是一项技术,允许我们可以将单个事件监听器附加到一个共同的父级元素,然后通过事件对象来确定哪个子元素触发事件。通过这种方式,我们可以使用单个事件监听器处理多个事件,并避免添加太多事件监听器到 DOM 中。

要实现事件委派,我们需要做两件事:

  1. 添加一个事件监听器到共同的父元素中。我们的示例中,对应的是带有 nav_links 类的元素。
  2. 使用事件对象来监测哪个子元素触发事件。我们的示例中,只需处理来自 nav_link 类的元素的事件。

以下是事件委派的代码示例:

document.querySelector('.nav__links').addEventListener('click', function(e) {
    e.preventDefault();
 
    if (!e.target.classList.contains('nav__link')) return

    const id = e.target.getAttribute('href');

    document.querySelector(id).scrollIntoView({
        behavior: 'smooth'
    });
});

该事件可以被任何子元素或者父元素本身触发。

我们只对来自于 nav_link 类的元素的事件感兴趣

匹配策略:我们使用事件 target 的 classList 属性去监测其是否包含 nav_link 类

匹配策略是此处最重要的部分,请根据你自己的代码对其进行调整

比如,如果其中一个 nav__link 有多个 child,上述策略将会失效。 

 <a class="nav__link" href="#section--3">
    <span>[Child]</span>
    Testimonials
 </a>

这种情况下,JavaScript 选择器的 closest() 变得很方便

  // ...

  const navLinkEl = e.target.closest('.nav__link');
 
  const id = navLinkEl.getAttribute('href');

  // ....

如你所见,我们将事件监听器的数量从 N (链接数) 减少到了 1 (父元素)。这就改进的网页的性能以及内存使用,并让代码更可维护、可伸缩。

结论

事件委派是一种强大的技术,可以帮助我们优化 JavaScript 代码,并使用单个事件监听器处理多个事件。它基于事件冒泡的概念,这意味着发生在子元素上的事件将传播到其父元素,直到到达 DOM 对象。通过使用事件委派,我们可以利用这种行为,并在 DOM 层次结构中的更高级别处理事件。

我希望你喜欢这篇文章,并了解到一些关于事件委派的新知识。如果您有任何问题或反馈,请在下面留言。感谢您的阅读!