前端小知识:事件委托及其应用

简介: 本文通过实际案例介绍前端中的事件委托及其应用。

前端小知识事 件 委 托


作者李俊才 (jcLee95)https://blog.csdn.net/qq_28550263

邮箱 :291148484@163.com

本文地址https://blog.csdn.net/qq_28550263/article/details/132819265


【介绍】:本文介绍前端中的事件委托。

上一节:《 上一节标题 | 下一节:《 下一节标题


目 录



1. 引例

考虑下面一个问题:

  • 当我们在前端开发中遇到需要 为一组相似的元素绑定事件处理程序 的情况时,通常会面临一个问题:为每个元素都创建一个独立的事件处理函数——这种方式是否是好?

我们将通过下面这个例子来说明这个问题和委托的概念。

【问题描述】:

  • 假设我们有一个网页,其中包含一个购物车,里面有很多商品项,每个商品项都有一个"添加到购物车"按钮。
  • 我们希望当用户点击这些按钮时能够执行相同的操作,即将商品添加到购物车,并更新购物车的显示。

一种最简单的方式是为每个按钮分别绑定点击事件处理程序,就像这样:

<ulid="cart"><li><span>商品1</span><buttonclass="add-to-cart">添加到购物车</button></li><li><span>商品2</span><buttonclass="add-to-cart">添加到购物车</button></li><!-- 更多商品项... --></ul><script>constaddToCartButtons=document.querySelectorAll('.add-to-cart');
addToCartButtons.forEach(button=> {
button.addEventListener('click', function() {
// 执行添加到购物车的逻辑// 更新购物车显示  });
});
</script>

尽管上述代码在功能上是可行的,但它存在一个潜在问题:

  • 为每个按钮都创建一个单独的事件处理函数。
  • 可以想象——当有大量商品时会导致创建大量相似的函数实例,占用大量内存。

2. 事件冒泡

事件冒泡(Event Bubbling)是指在处理DOM事件时,事件会从触发它的最内层元素开始冒泡,逐级向上传播,一直传递到根元素(通常是或),直到被停止或取消。这意味着如果一个子元素触发了某个事件,那么这个事件也会逐级传递给该子元素的父元素,以及父元素的父元素,以此类推。

事件冒泡的工作流程如下:

  1. 首先,用户在页面上的某个元素上触发了一个事件,比如点击鼠标或触摸屏幕;
  2. 事件首先被分派到触发事件的 最内层元素(目标元素),并在该元素上 执行绑定的事件处理程序
    3.然后,事件开始冒泡,向上级元素传递,一层一层地触发父元素上的相同事件;
    4.当事件到达文档根部(通常是元素)时,它可能会 停止冒泡,也可能继续传递到浏览器层面,(根据事件是否被取消来决定)。

在这个过程中,任何父元素上绑定的事件处理程序都可能被触发,包括目标元素本身的父元素、爷爷元素、曾祖父元素,以及文档根元素等。

3. 事件冒泡是委托的实现依据

在第1小节的案例中,我们提到了一个小缺陷。也iu是,为每个按钮都创建一个单独的事件处理函数,可能导致大量商品时会导致创建大量相似的函数实例,占用大量内存。

这时,我们联想起冒泡机制:

  • 冒泡机制使得事件 可以在DOM结构中传递并被多个元素捕获。这允许我们 在父元素上捕获子元素的事件,从而减少事件处理程序的数量,提高性能和可维护性。

事实上,冒泡机制也是事件委托模式的基础。

结合第1小节的案例来看,当用户点击任何一个"添加到购物车"按钮时,事件会冒泡到

    元素,我们可以在父元素上处理事件,修改被修改的那部分代码如下:
<script>constcart=document.getElementById('cart');
cart.addEventListener('click', function(event) {
if (event.target.classList.contains('add-to-cart')) {
// 执行添加到购物车的逻辑// 更新购物车显示  }
});
</script>

修改后的脚本相比于第1小节中的脚本的主要不同之处在于——事件处理的位置。

在第1小节中,事件处理程序是直接绑定在每个 “添加到购物车” 按钮上,使用了 button.addEventListener。这意味着每个按钮都有自己的独立事件处理程序,当用户点击其中一个按钮时,只会触发与该按钮关联的事件处理程序:

addToCartButtons.forEach(button=> {
button.addEventListener('click', function() {
// 执行添加到购物车的逻辑// 更新购物车显示  });
});

而修改后的脚本,事件处理程序是绑定在购物车容器

    上,使用了 cart.addEventListener。然后,在事件处理程序内部,通过检查 event.target来确定触发事件的元素是否包含类名 ‘add-to-cart’。如果是,就执行相应的逻辑:
constcart=document.getElementById('cart');
cart.addEventListener('click', function(event) {
if (event.target.classList.contains('add-to-cart')) {
// 执行添加到购物车的逻辑// 更新购物车显示  }
});

这样修改有什么好处呢:

  • 前者每个按钮都有自己的事件处理程序,这在逻辑上更容易理解,但当有大量按钮时,会导致创建多个函数实例,可能占用更多内存。
  • 后者只有一个事件处理程序绑定在购物车容器上,这可以减少内存占用,提高性能,因为只有一个事件处理程序实例。

后者这种利用事件的冒泡特性,将多个子元素的同一类型的监听器合并到父元素上来实现的方式就被称作所谓的事件委托。

4. 另一个场景:动态生成的元素的事件绑定

事件委托的思想还可以应用于 监听 动态生成的元素和动态绑定事件。

动态生成的元素 是指 在页面加载后 通过JavaScript代码创建的元素——由于这些元素并不存在于初始HTML中,因此不能像静态元素那样直接绑定事件处理程序

让我们通过一个具体的例子来详细讲解——如何使用事件委托来监听和处理动态生成的元素的事件。

假设我们有一个按钮,点击它将在页面上动态创建一个新的列表项(<li>元素),然后我们希望能够点击这些动态创建的列表项并执行一些操作,比如改变它们的样式或进行其他操作。代码如下。

<!DOCTYPE html><html><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>动态元素事件委托案例</title></head><body><ulid="dynamic-list"><!-- 这里没有任何<li>元素 --></ul><buttonid="add-button">添加列表项</button><script>constdynamicList=document.getElementById('dynamic-list');
constaddButton=document.getElementById('add-button');
// 点击按钮时,动态创建一个新的列表项addButton.addEventListener('click', function() {
constnewItem=document.createElement('li');
newItem.textContent='新的列表项';
dynamicList.appendChild(newItem);
    });
// 事件委托,监听<ul>上的点击事件dynamicList.addEventListener('click', function(event) {
if (event.target.tagName==='LI') {
// 当点击列表项时,执行操作event.target.style.backgroundColor='lightblue';
      }
    });
</script></body></html>

本例中,有一个 添加按钮(addButton)和一个空的 无序列表(dynamicList)。

  • 当用户点击按钮时,动态创建一个新的列表项(<li>元素),并将其添加到列表中。
  • 我们使用事件委托将点击事件绑定到<ul>元素上,监听了所有<li>元素的点击事件。

无论何时点击动态生成的列表项,事件都会冒泡到<ul>元素,事件处理程序检查被点击的元素是否是<li>元素,如果是,就执行相应的操作。在本例中,我们改变了被点击的列表项的背景颜色。效果如图所示:

从本例可以看到,这种方式下,我们能够动态绑定事件处理程序而不需要为每个列表项都手动绑定——因此,无论有多少个列表项,代码都能完成处理。

目录
相关文章
|
1月前
|
前端开发 JavaScript 安全
前端性能调优:HTTP/2与HTTPS在Web加速中的应用
【10月更文挑战第27天】本文介绍了HTTP/2和HTTPS在前端性能调优中的应用。通过多路复用、服务器推送和头部压缩等特性,HTTP/2显著提升了Web性能。同时,HTTPS确保了数据传输的安全性。文章提供了示例代码,展示了如何使用Node.js创建一个HTTP/2服务器。
60 3
|
23天前
|
移动开发 缓存 前端开发
深入理解前端路由:原理、实现与应用
本书《深入理解前端路由:原理、实现与应用》全面解析了前端路由的核心概念、工作原理及其实现方法,结合实际案例探讨了其在现代Web应用中的广泛应用,适合前端开发者和相关技术人员阅读。
|
1月前
|
前端开发 项目管理
Gitflow分支策略及其在前端工程化中的应用
Gitflow 分支策略也并非适用于所有项目。对于一些小型或简单的前端项目,可能会显得过于复杂。在实际应用中,需要根据项目的具体情况和团队的需求进行适当调整和优化。
|
29天前
|
自然语言处理 前端开发 JavaScript
深入理解前端中的 “this” 指针:从基础概念到复杂应用
本文全面解析前端开发中“this”指针的运用,从基本概念入手,逐步探讨其在不同场景下的表现与应用技巧,帮助开发者深入理解并灵活掌握“this”的使用。
|
29天前
|
存储 前端开发 JavaScript
前端中对象的深度应用与最佳实践
前端对象应用涉及在网页开发中使用JavaScript等技术创建和操作对象,以实现动态交互效果。通过定义属性和方法,对象可以封装数据和功能,提升代码的组织性和复用性,是现代Web开发的核心技术之一。
|
1月前
|
前端开发
结合具体案例分析Gitflow分支策略在大型前端项目中的应用优势
通过这个具体案例可以看出,Gitflow 分支策略在大型前端项目中能够提供有条不紊的开发环境,保障项目的稳定性和持续发展。
|
1月前
|
缓存 JavaScript 前端开发
JavaScript 与 DOM 交互的基础及进阶技巧,涵盖 DOM 获取、修改、创建、删除元素的方法,事件处理,性能优化及与其他前端技术的结合,助你构建动态交互的网页应用
本文深入讲解了 JavaScript 与 DOM 交互的基础及进阶技巧,涵盖 DOM 获取、修改、创建、删除元素的方法,事件处理,性能优化及与其他前端技术的结合,助你构建动态交互的网页应用。
45 5
|
1月前
|
前端开发 开发者
本文将深入探讨 BEM 的概念、原理以及其在前端开发中的应用
BEM(Block-Element-Modifier)是一种前端开发中的命名规范和架构方法,旨在提高代码的可维护性和复用性。通过将界面拆分为独立的模块,BEM 提供了一套清晰的命名规则,增强了代码的结构化和模块化设计,促进了团队协作。本文深入探讨了 BEM 的概念、原理及其在前端开发中的应用,分析了其优势与局限性,为开发者提供了宝贵的参考。
52 8
|
1月前
|
JavaScript 前端开发 测试技术
构建高效可维护的前端应用
构建高效可维护的前端应用
|
1月前
|
编解码 监控 JavaScript
打造高效前端应用
打造高效前端应用
35 1