当前位置: 首页 > news >正文

【前端】详解JavaScript事件代理(事件委托)

在这里插入图片描述

😎 作者介绍:我是程序员洲洲,一个热爱写作的非著名程序员。CSDN全栈优质领域创作者、华为云博客社区云享专家、阿里云博客社区专家博主。
🤓 同时欢迎大家关注其他专栏,我将分享Web前后端开发、人工智能、机器学习、深度学习从0到1系列文章。
🌼 同时洲洲已经建立了程序员技术交流群,如果您感兴趣,可以私信我加入社群,可以直接vx联系(文末有名片)v:bdizztt
🖥 随时欢迎您跟我沟通,一起交流,一起成长、进步!点此也可获得联系方式~

本文目录

  • 前言
  • 一、事件冒泡
  • 二、代码实现
    • 2.1 JavaScript原生实现
    • 2.2 jQuery事件delegate()实现
    • 2.3 动态添加元素
  • 三、实战案例解析
  • 四、注意事项
  • 总结

前言

事件代理(Event Delegation),又称之为事件委托。是JavaScript中常用绑定事件的常用技巧。

顾名思义,“事件代理”即是把原本需要绑定在子元素的响应事件(click、keydown…)委托给父元素,让父元素担当事件监听的职务。


事件代理的原理是DOM元素的事件冒泡。

我们举一个通俗的例子来进行说明:

比如一个宿舍的同学同时快递到了,一种方法就是他们一个个去领取,还有一种方法就是把这件事情委托给宿舍长,让一个人出去拿好所有快递,然后再根据收件人一 一分发给每个宿舍同学。

在这里,取快递就是一个事件,每个同学指的是需要响应事件的 DOM 元素,而出去统一领取快递的宿舍长就是代理的元素,所以真正绑定事件的是这个元素,按照收件人分发快递的过程就是在事件执行中,需要判断当前响应的事件应该匹配到被代理元素中的哪一个或者哪几个。

一、事件冒泡

在JavaScript编程中,事件代理(Event Delegation)是一种将事件监听器应用于一个父元素,而不是直接应用于每一个子元素的技术。


这种方法可以提高性能,尤其是在处理大量元素时。本文将详细介绍事件代理的概念、原理、使用场景、代码示例以及注意事项。

所以在了解事件代理之前,我们需要知道什么是事件冒泡(Event Bubbling)。

当一个事件在DOM元素上触发时,它会首先在该元素上触发,然后逐级向上传播到文档的根元素。这个过程就是事件冒泡。

事件传播分成三个阶段:

  • 捕获阶段:从window对象传导到目标节点(上层传到底层)称为“捕获阶段”(capture phase),捕获阶段不会响应任何事件;
  • 目标阶段:在目标节点上触发,称为“目标阶段”
  • 冒泡阶段:从目标节点传导回window对象(从底层传回上层),称为“冒泡阶段”(bubbling
    phase)。事件代理即是利用事件冒泡的机制把里层所需要响应的事件绑定到外层;

事件代理利用了事件冒泡的原理。通过在父元素上设置监听器,可以捕获到在其子元素上触发的事件。因为事件会从子元素冒泡到父元素,所以父元素上的监听器可以处理这些事件。

优点

  • 减少内存消耗:不需要为每个子元素分别添加事件监听器。
  • 提高性能:特别是在动态生成的元素上,不需要为新元素重新绑定事件。
  • 简化代码:统一处理事件,代码更简洁。

我们通过代码来看看优点:可以大量节省内存占用,减少事件注册,比如在ul上代理所有li的click事件。

<ul id="myList"><li>列表项 1</li><li>列表项 2</li><li>列表项 3</li><!-- 更多列表项 -->
</ul>

如上面代码所示,如果给每个li列表项都绑定一个函数,那对内存的消耗是非常大的,因此较好的解决办法就是将li元素的点击事件绑定到它的父元素ul身上,执行事件的时候再去匹配判断目标元素。

假设上述的例子中列表项li就几个,给每个列表项都绑定了事件。

但是在很多时候,需要通过 AJAX 或者用户操作动态的增加或者删除列表项li元素,那么在每一次改变的时候都需要重新给新增的元素绑定事件,给即将删去的元素解绑事件。

如果用了事件委托就没有这种麻烦了,因为事件是绑定在父层的,和目标元素的增减是没有关系的,执行到目标元素是在真正响应执行事件函数的过程中去匹配的;所以使用事件在动态绑定事件的情况下是可以减少很多重复工作的。

缺点

  • 事件类型限制:只能捕获冒泡的事件,不能捕获不冒泡的事件。
  • 事件对象处理:需要通过事件对象的属性来确定事件的真正来源。

二、代码实现

2.1 JavaScript原生实现

<ul id="myLinks"><li id="goSomewhere">Go somewhere</li><li id="doSomething">Do something</li><li id="sayHi">Say hi</li>
</ul>

需要像下面这样为它们添加 3 个事 件处理程序:

    var item1 = document.getElementById("goSomewhere");var item2 = document.getElementById("doSomething");var item3 = document.getElementById("sayHi");item1.onclick = function() {location.href = "http://www.baidu.com";};item2.onclick = function() {document.title = "事件委托";};item3.onclick = function() {alert("hi");};

如果在一个复杂的 Web 应用程序中,对所有可单击的元素都采用这种方式,那么结果就会有数不 清的代码用于添加事件处理程序。

此时,可以利用事件委托技术解决这个问题。

使用事件委托,只需在 DOM 树中尽量最高的层次上添加一个事件处理程序,如下所示:

    var item1 = document.getElementById("goSomewhere");var item2 = document.getElementById("doSomething");var item3 = document.getElementById("sayHi");document.addEventListener("click", function (event) {var target = event.target;switch (target.id) {case "doSomething":document.title = "事件委托";break;case "goSomewhere":location.href = "http://www.baidu.com";break;case "sayHi": alert("hi");break;}})

或者代码:

document.getElementById('myList').addEventListener('click', function(event) {if (event.target.tagName === 'LI') {console.log('你点击了:', event.target.textContent);}
});

2.2 jQuery事件delegate()实现

delegate() 方法为指定的元素(属于被选元素的子元素)添加一个或多个事件处理程序,并规定当这些事件发生时运行的函数。

格式:$(selector).delegate(childSelector, event, data, function)

childSelector:必需,规定要附加事件处理程序的一个或多个子元素。
event:必需,规定附加到元素的一个或多个事件。由空格分隔多个事件值。必须是有效的事件。
data:可选,规定传递到函数的额外数据。
function:必需,规定当事件发生时运行的函数。

<!DOCTYPE html>
<html><head><meta charset="utf-8"><script src="http://lib.sinaapp.com/js/jquery/2.0.2/jquery-2.0.2.min.js"></script>
</head><body><ul id="myLinks"><li id="goSomewhere">Go somewhere</li><li id="doSomething">Do something</li><li id="sayHi">Say hi</li></ul><script>$(document).ready(function () {$("#myLinks").delegate("#goSomewhere", "click", function () {location.href = "http://www.baidu.com";});});</script></body></html>

2.3 动态添加元素

function addItem() {var newItem = document.createElement('li');newItem.textContent = '新列表项';document.getElementById('myList').appendChild(newItem);
}// 即使使用事件代理,新添加的列表项也会有点击事件
addItem();

三、实战案例解析

假设我们有一个图片库,用户点击任何图片时,需要显示图片的描述:

<div id="gallery"><img src="image1.jpg" alt="图片1" title="这是图片1的描述"><img src="image2.jpg" alt="图片2" title="这是图片2的描述"><!-- 更多图片 -->
</div>

使用事件代理,我们可以这样实现:

document.getElementById('gallery').addEventListener('click', function(event) {if (event.target.tagName === 'IMG') {alert(event.target.title);}
});

四、注意事项

事件类型:确保使用的事件类型支持冒泡,如 click、mouseover 等。

事件委托链:避免在多个元素上设置相同类型的事件代理,这可能导致事件处理逻辑混乱。

事件对象:正确使用 event.target 或 event.currentTarget 来区分事件的来源。

性能考虑:虽然事件代理可以减少内存消耗,但在某些情况下,如事件处理逻辑非常复杂,可能会影响性能。

兼容性:事件代理在所有现代浏览器中都得到支持,但在老旧浏览器中可能存在问题。

总结

📝Hello,各位看官老爷们好,我已经建立了CSDN技术交流群,如果你很感兴趣,可以私信我加入我的社群。

📝社群中不定时会有很多活动,例如每周都会包邮免费送一些技术书籍及精美礼品、学习资料分享、大厂面经分享、技术讨论谈等等。

📝社群方向很多,相关领域有Web全栈(前后端)、人工智能、机器学习、自媒体副业交流、前沿科技文章分享、论文精读等等。

📝不管你是多新手的小白,都欢迎你加入社群中讨论、聊天、分享,加速助力你成为下一个大佬!

📝想都是问题,做都是答案!行动起来吧!欢迎评论区or后台与我沟通交流,也欢迎您点击下方的链接直接加入到我的交流社群!~ 跳转链接社区~

在这里插入图片描述

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • ---java 抽象类 和 接口---
  • 【设计模式】行为型设计模式之 迭代器模式
  • LeetCode 算法:合并区间c++
  • 封装了一个简单理解的iOS竖直文字轮播
  • k8s学习--kubernetes服务自动伸缩之水平收缩(pod副本收缩)VPA策略应用案例
  • Wireshark TS | 应用传输丢包问题
  • No ‘ChromeSansMM’ font 错误解决
  • 渗透测试之内核安全系列课程:Rootkit技术初探(一)
  • vue面试题2-根据以下问题回答
  • ChatGP和kimi对比
  • Docker之路(三)docker安装nginx实现对springboot项目的负载均衡
  • Java 程序结构 -- Java 语言的变量、方法、运算符与注释
  • Apache Spark
  • 解释一下I/O多路复用模型?
  • 单元测试覆盖率
  • AHK 中 = 和 == 等比较运算符的用法
  • co模块的前端实现
  • CSS中外联样式表代表的含义
  • JavaWeb(学习笔记二)
  • Mysql数据库的条件查询语句
  • nodejs实现webservice问题总结
  • npx命令介绍
  • React Transition Group -- Transition 组件
  • Sass Day-01
  • 关于 Cirru Editor 存储格式
  • 基于阿里云移动推送的移动应用推送模式最佳实践
  • 聊聊springcloud的EurekaClientAutoConfiguration
  • 深度学习中的信息论知识详解
  • 使用agvtool更改app version/build
  • 手机端车牌号码键盘的vue组件
  • 网页视频流m3u8/ts视频下载
  • 系统认识JavaScript正则表达式
  • k8s使用glusterfs实现动态持久化存储
  • 带你开发类似Pokemon Go的AR游戏
  • 关于Android全面屏虚拟导航栏的适配总结
  • ​1:1公有云能力整体输出,腾讯云“七剑”下云端
  • ​渐进式Web应用PWA的未来
  • ​什么是bug?bug的源头在哪里?
  • ${ }的特别功能
  • $HTTP_POST_VARS['']和$_POST['']的区别
  • (2022 CVPR) Unbiased Teacher v2
  • (JSP)EL——优化登录界面,获取对象,获取数据
  • (八十八)VFL语言初步 - 实现布局
  • (待修改)PyG安装步骤
  • (附源码)计算机毕业设计ssm基于B_S的汽车售后服务管理系统
  • (回溯) LeetCode 131. 分割回文串
  • (四)【Jmeter】 JMeter的界面布局与组件概述
  • (算法)求1到1亿间的质数或素数
  • (微服务实战)预付卡平台支付交易系统卡充值业务流程设计
  • (学习日记)2024.02.29:UCOSIII第二节
  • (一)Thymeleaf用法——Thymeleaf简介
  • (一)认识微服务
  • (转)setTimeout 和 setInterval 的区别
  • (转)淘淘商城系列——使用Spring来管理Redis单机版和集群版
  • *Algs4-1.5.25随机网格的倍率测试-(未读懂题)