事件委派:一项改进 JavaScript 性能的技术
摘要
本文将介绍事件委派是什么,以及它如何通过减少事件监听的数量优化 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 中。
要实现事件委派,我们需要做两件事:
- 添加一个事件监听器到共同的父元素中。我们的示例中,对应的是带有 nav_links 类的元素。
- 使用事件对象来监测哪个子元素触发事件。我们的示例中,只需处理来自 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 层次结构中的更高级别处理事件。
我希望你喜欢这篇文章,并了解到一些关于事件委派的新知识。如果您有任何问题或反馈,请在下面留言。感谢您的阅读!