前端中的事件委托

前端小知识
事 件 委 托

作者李俊才 (jcLee95):https://blog.csdn.net/qq_28550263
邮箱 :291148484@163.com
本文地址:https://blog.csdn.net/qq_28550263/article/details/132819265


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

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


1. 引例

考虑下面一个问题:

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

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

【问题描述】:

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

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

<ul id="cart"><li><span>商品1</span><button class="add-to-cart">添加到购物车</button></li><li><span>商品2</span><button class="add-to-cart">添加到购物车</button></li><!-- 更多商品项... -->
</ul><script>
const addToCartButtons = 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>
const cart = 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’。如果是,就执行相应的逻辑:

const cart = document.getElementById('cart');cart.addEventListener('click', function(event) {if (event.target.classList.contains('add-to-cart')) {// 执行添加到购物车的逻辑// 更新购物车显示}
});

这样修改有什么好处呢:

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

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

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

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

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

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

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

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>动态元素事件委托案例</title>
</head>
<body><ul id="dynamic-list"><!-- 这里没有任何<li>元素 --></ul><button id="add-button">添加列表项</button><script>const dynamicList = document.getElementById('dynamic-list');const addButton = document.getElementById('add-button');// 点击按钮时,动态创建一个新的列表项addButton.addEventListener('click', function() {const newItem = 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>元素,如果是,就执行相应的操作。在本例中,我们改变了被点击的列表项的背景颜色。效果如图所示:

在这里插入图片描述

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/106456.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

T2I-Adapter:增强文本到图像生成的控制能力

链接&#xff1a;GitHub - TencentARC/T2I-Adapter: T2I-Adapter 文本到图像生成 (T2I) 是人工智能领域的一个重要研究方向。近年来&#xff0c;随着深度学习技术的发展&#xff0c;T2I 技术取得了显著进展&#xff0c;生成的图像在视觉效果上已经与真实图像难以区分。 然而&…

解决nbsp;不生效的问题

代码块 {{title}} title:附 \xa0\xa0\xa0件,//或者 <span v-html"title"></span> title:附 件&#xff1a;,效果图

机器学习(10)---特征选择

文章目录 一、概述二、Filter过滤法2.1 过滤法说明2.2 方差过滤2.3 方差过滤对模型影响 三、相关性过滤3.1 卡方过滤3.2 F检验3.3 互信息法3.4 过滤法总结 四、Embedded嵌入法4.1 嵌入法说明4.2 以随机森林为例的嵌入法 五、Wrapper包装法5.1 包装法说明5.2 以随机森林为例的包…

Sql注入详解(原理篇)

一、简介 SQL 注入漏洞非常复杂&#xff0c;区分各种数据库类型&#xff0c;提交方法&#xff0c;数据类型等注入&#xff0c;同样此类漏洞是WEB安全中严重的安全漏洞&#xff0c;学习如何利用&#xff0c;挖掘&#xff0c;修复也是很重要的 二、SQL注入原理 1、什么是SQL注…

蓝桥杯官网练习题(纸牌三角形)

题目描述 本题为填空题&#xff0c;只需要算出结果后&#xff0c;在代码中使用输出语句将所填结果输出即可。 A,2,3,4,5,6,7,8,9 共 99 张纸牌排成一个正三角形&#xff08;A 按 1 计算&#xff09;。要求每个边的和相等。 下图就是一种排法。 这样的排法可能会有很多。 如果…

RK3399平台开发系列讲解(内核调试篇)USB摄像头快速测试

🚀返回专栏总目录 文章目录 一、检测设备二、安装必要的库三、 mjpeg-stream 安装四、实时预览沉淀、分享、成长,让自己和他人都能有所收获!😄 📢 本篇介绍如何快速测试 USB 摄像头。 一、检测设备 将 USB 摄像头插上,查看是否找到设备,输入指令:v4l2-ctl --list-d…

数据结构:线性表之-循环双向链表(万字详解)

目录 基本概念 1&#xff0c;什么是双向链表 2&#xff0c;与单向链表的区别 双向链表详解 功能展示&#xff1a; 1. 定义链表 2&#xff0c;创建双向链表 3&#xff0c;初始化链表 4,尾插 5&#xff0c;头插 6&#xff0c;尾删 判断链表是否被删空 尾删代码 7&a…

.net 7 隐藏swagger的api

1.写一个隐藏接口特性表示 using Microsoft.AspNetCore.Mvc.ApiExplorer; using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen;using System.Web.Http.Description;namespace JiaTongInterface.Filter {public class SwaggerApi : Swashbuckle.AspNet…

JavaScript Promise 的真正工作原理

Promise 是处理异步代码的一种技术,也称为脱离回调地狱的头等舱门票。 3 承诺状态 待定状态 已解决状态 拒绝状态 理解 JavaScript Promis 什么是承诺? 通常,承诺被定义为最终可用的值的代理。 Promise 多年来一直是 JavaScript 的一部分(在 ES2015 中标准化并引入)。最…

青骨申报|CSC管理信息平台使用指南

2023年青年骨干教师出国研修项目于9月10-25日网上报名&#xff0c;为此知识人网小编特转载最新版本的国家留学基金委&#xff08;CSC&#xff09;国家公派留学管理信息平台使用指南&#xff08;国内申请访学类&#xff09;&#xff0c;以方便申报者查阅。 提示&#xff1a;国家…

【算法专题突破】双指针 - 最大连续1的个数 III(11)

目录 1. 题目解析 2. 算法原理 3. 代码编写 写在最后&#xff1a; 1. 题目解析 题目链接&#xff1a;1004. 最大连续1的个数 III - 力扣&#xff08;Leetcode&#xff09; 这道题不难理解&#xff0c;其实就是求出最长的连续是1的子数组&#xff0c; 但是&#xff0c;他支…

解决jsp/html界面跳转servlet出现404错误的方法

解决jsp/html界面跳转servlet出现404错误的方法 最近在学习黑马项目过程中遇到的问题 问题一&#xff1a; 检查页面的跳转路径和名称拼写是否正确 问题二&#xff1a; tomcat发布项目时所使用的路径名称与项目不同 在idea右上角点击如图圈住的按钮 在deployment中更改出现…