JS中给元素添加事件监听器的各种方法详解(包含比较和应用场景)
JavaScript 中给元素添加事件监听器的各种方法详解
在 JavaScript 中,事件处理是前端开发的一个重要部分。无论是点击按钮、提交表单,还是鼠标悬停,都涉及到事件监听。本文中,我将详细讲解各种给元素添加事件监听器的方法,包括每种方法的优缺点、实际示例、使用场景及彼此的对比。
1. 使用 HTML 中的事件属性(Inline Event Handlers)
这是早期最直接的事件绑定方式,直接在 HTML 元素的标签中指定事件处理程序。
示例:
<button onclick="handleClick()">Click me</button><script>function handleClick() {alert('Button clicked!');}
</script>
优点:
- 简单直接:事件逻辑直接嵌入到 HTML 标签中,易于理解,特别是初学者快速上手。
- 快速实现交互:对于简单的交互,可以快速实现。
缺点:
- 污染 HTML:JavaScript 代码直接嵌入到 HTML 中,破坏了代码的分离性,不利于维护和复用。
- 只能绑定一个事件处理程序:因为事件处理程序直接定义在标签属性中,只能绑定一个处理程序,无法绑定多个。
- 难以维护:当项目变得复杂时,内联事件会让 HTML 和逻辑混合在一起,维护困难。
使用场景:
适用于非常简单或一次性的功能,快速展示页面交互功能时可用。
2. 使用 JavaScript 中的 DOM 元素的事件属性
这种方式是在 JavaScript 中直接通过 DOM 元素的事件属性(如 onclick)来绑定事件处理程序。事件处理函数是在 JavaScript 逻辑中,而不是嵌入到 HTML 标签中。
示例:
<button id="myButton">Click me</button><script>const btn = document.getElementById('myButton');btn.onclick = function() {alert('Button clicked!');};
</script>
优点:
- 与 HTML 代码分离:JavaScript 逻辑与 HTML 结构分离,代码稍微更干净,便于理解。
- 简单易懂:直接通过元素属性来添加事件,与内联事件处理类似,但更具灵活性。
缺点:
-
覆盖问题:对于同一个事件类型,只能绑定一个处理程序。后绑定的处理程序会覆盖之前绑定的。例如,绑定多个
onclick处理程序时,只会保留最后一个。覆盖示例:
const btn = document.getElementById('myButton'); btn.onclick = function() {alert('First handler'); };// 覆盖了上面的事件处理程序 btn.onclick = function() {alert('Second handler'); }; -
不支持事件委托:无法通过事件冒泡来处理动态生成的子元素的事件。
使用场景:
适用于简单的项目,且每个元素只需绑定一个事件处理程序的场景。
3. 使用 addEventListener() 方法
这是现代浏览器推荐的事件绑定方式。addEventListener() 方法不仅可以为同一元素添加多个事件监听器,还可以控制事件的捕获和冒泡行为。相比 onclick 等直接绑定事件的方法,它提供了更强的灵活性。
基本使用示例:
<button id="myButton">Click me</button><script>const btn = document.getElementById('myButton');btn.addEventListener('click', function() {alert('Button clicked!');});
</script>
绑定多个事件处理程序:
addEventListener() 允许为同一元素的同一事件类型添加多个事件处理程序。
const btn = document.getElementById('myButton');// 第一个事件处理程序
btn.addEventListener('click', function() {alert('First handler');
});// 第二个事件处理程序
btn.addEventListener('click', function() {alert('Second handler');
});// 点击按钮时,依次触发两个事件处理程序
解除事件监听器:
可以使用 removeEventListener() 来移除绑定的事件处理程序。注意,移除事件处理程序时,必须传递与绑定时完全相同的函数引用,匿名函数无法移除。
const btn = document.getElementById('myButton');function handleClick() {alert('Button clicked!');
}// 绑定事件
btn.addEventListener('click', handleClick);// 解除事件绑定
btn.removeEventListener('click', handleClick);
第三个参数(控制事件捕获与冒泡):
addEventListener() 的第三个参数可以是一个布尔值或对象,用来控制事件是在捕获阶段还是冒泡阶段触发。
- 事件捕获:从根元素开始向目标元素传播。
- 事件冒泡:从目标元素开始向根元素传播(这是默认行为)。
捕获阶段示例:
const btn = document.getElementById('myButton');// 捕获阶段处理事件
btn.addEventListener('click', function() {alert('Captured click event');
}, true); // 第三个参数为 true 表示捕获阶段
对象作为第三个参数:
btn.addEventListener('click', function() {alert('Button clicked with options');
}, { capture: true, once: true });
capture: true:表示在捕获阶段触发事件。once: true:表示事件处理程序仅执行一次后自动移除。
优点:
- 支持多个事件处理程序:同一事件类型可以绑定多个事件处理程序,按顺序依次执行。
- 细粒度控制:可以通过第三个参数控制事件是在捕获还是冒泡阶段触发。
- 可移除监听器:支持使用
removeEventListener()解除事件监听。 - 支持事件委托:可通过事件冒泡机制来进行事件委托,处理动态生成的子元素事件。
缺点:
- 老旧浏览器兼容性:在非常老的浏览器(如 IE8 及以下)中不支持,需使用
attachEvent()替代。
使用场景:
适用于现代 Web 开发的所有场景,尤其适合需要为同一元素绑定多个事件处理程序、或者需要精细控制事件阶段的情况。
4. 事件委托(Event Delegation)
事件委托是一种优化事件处理的技术,它利用事件冒泡机制,通过在父级元素上绑定事件监听器,来处理多个子元素的事件。对于动态生成的子元素或大量子元素来说,事件委托能显著提升性能和代码简洁度。
示例:
<ul id="parent"><li>Item 1</li><li>Item 2</li><li>Item 3</li>
</ul><script>const parent = document.getElementById('parent');parent.addEventListener('click', function(event) {if (event.target.tagName === 'LI') {alert('You clicked: ' + event.target.textContent);}});
</script>
在这个例子中,只需在父级 ul 元素上绑定一个点击事件监听器,就可以处理所有 li 元素的点击事件。这对于动态添加的 li 元素同样有效。
优点:
- 性能优化:通过减少绑定的事件处理程序数量,降低内存消耗,提升性能,特别是对于动态生成的大量子元素。
- 动态元素支持:即使是通过 JavaScript 动态添加的元素,也能通过事件委托进行事件处理。
- 代码简洁:避免为每个子元素分别绑定事件处理程序。
缺点:
- 不适用于不冒泡的事件:例如
focus和blur事件,这些事件不会冒泡,因此不能通过事件委托来处理。 - 需要手动筛选目标:事件冒泡时,父级元素会捕捉到所有子元素的事件,开发者需要在事件处理程序中筛选
event.target来确定触发的具体元素。
使用场景:
适用于大量子元素事件处理,或者需要动态生成子元素的场景。例如表格、列表等大量 DOM 结构的事件处理。
5. attachEvent() 方法(仅用于 IE8 及以下)
这是旧版 IE 浏览器的事件绑定方法,与标准的 addEventListener() 类似,但有一些限制。
示例:
const btn = document.getElementById('myButton');
btn.attachEvent('onclick', function() {alert('Button clicked!');
});
优点:
- 兼容老旧浏览器:这是为了支持 IE8 及以下版本的旧式浏览器。
缺点:
- 非标准:
attachEvent()是 IE 专有的事件处理方式,不符合标准,现代浏览器不支持。 - **无法控制事件的捕获
和冒泡**:attachEvent() 无法像 addEventListener() 一样灵活控制事件的捕获和冒泡。
- 上下文问题:在
attachEvent中,this关键字总是指向window对象,而不是事件的目标元素,导致代码不一致。
使用场景:
仅用于需要兼容 IE8 及以下浏览器的项目中。但在现代开发中,通常不推荐使用。
总结
| 方法 | 优点 | 缺点 | 使用场景 |
|---|---|---|---|
| HTML 内联事件 | 简单、直观 | 代码难维护,无法绑定多个处理程序 | 非常简单的页面或一次性项目 |
| DOM 事件属性 | 简单、与 HTML 分离 | 覆盖问题,无法绑定多个处理程序 | 简单页面交互 |
| addEventListener() | 支持多个处理程序,解除事件监听,事件委托,控制捕获和冒泡 | 需要考虑老旧浏览器兼容性 | 现代 Web 开发,复杂交互场景 |
| 事件委托 | 性能好,支持动态元素 | 不适用于不冒泡的事件,手动筛选目标 | 动态子元素或大量子元素的事件处理 |
| attachEvent() | 兼容旧版 IE | 非标准,事件处理不一致 | 仅用于兼容 IE8 及以下 |
结论
在现代 Web 开发中,推荐使用 addEventListener(),它功能强大且灵活,适用于几乎所有的事件处理场景。而事件委托则是处理大量动态生成元素的最佳实践。对于非常简单的项目,可以考虑使用 DOM 事件属性。而内联事件处理和 attachEvent() 则不建议在现代开发中使用。
相关文章:
JS中给元素添加事件监听器的各种方法详解(包含比较和应用场景)
JavaScript 中给元素添加事件监听器的各种方法详解 在 JavaScript 中,事件处理是前端开发的一个重要部分。无论是点击按钮、提交表单,还是鼠标悬停,都涉及到事件监听。本文中,我将详细讲解各种给元素添加事件监听器的方法&#x…...
Python基本数据类型之复数complex
来源: “码农不会写诗”公众号 链接:Python基本数据类型之复数complex 文章目录 01 基本概念02 基本运算03 拓展1复数与向量 复数complex Python基本数据之复数(complex)即包含实部和虚部的数字。 01 基本概念 即包含实部和虚部的数字。 在Python中&am…...
第六届机器人与智能制造技术国际会议 (ISRIMT 2024)
目录 会议详情 主题 会议官网 会议详情 第六届机器人与智能制造技术国际研讨会(ISRIMT 2024)计划于2024年9月20-22日在常州举行。会议主要聚焦“机器人”和“智能制造技术”的研究领域,旨在为机器人和智能制造技术领域的专家学者、工程技术…...
鸿蒙轻内核M核源码分析系列十九 Musl LibC
往期知识点记录: 鸿蒙(HarmonyOS)应用层开发(北向)知识点汇总 轻内核M核源码分析系列一 数据结构-双向循环链表 轻内核M核源码分析系列二 数据结构-任务就绪队列 鸿蒙轻内核M核源码分析系列三 数据结构-任务排序链表 轻…...
mysqldump备份恢复数据库
mysqldump程序可以用来备份和恢复数据库 ,默认情况mysqldump会创建drop table, create table,和insert into的sql语句. 语法 > mysqldump [options] db_name [tbl_name ...] > mysqldump [options] --databases db_name ... > mysqldump [options] --all-databases备…...
路径规划——RRT算法
路径规划——RRT算法 算法原理 RRT算法的全称是快速扩展随机树算法(Rapidly Exploring Random Tree),它的思想是选取一个初始点作为根节点,通过随机采样,增加叶子节点的方式,生成一个随机扩展树,当随机树中的叶子节点…...
OPCUA-PLC
下载opcua服务器(有PLC可以直连),UaAnsiCServer下载路径 双击运行如下,Endpoint显示opcua服务路径 opc.tcp://DESKTOP-9SD7K4B:48020 下载opcua客户端(类似编写代码连接操作),UaExpert下载路径 如果连接失败,有一个授权认证,点击同意就行 java代码实现连接opcUA操作 pom.…...
在Windows系统上部署PPTist并实现远程访问
在Windows系统上部署PPTist并实现远程访问 前言PPTist简介本地部署PPTist步骤1:获取PPTist步骤2:安装依赖步骤3:运行PPTist 使用PPTist远程访问PPTist步骤1:安装Cpolar步骤2:配置公网地址步骤3:配置固定公网…...
【Grafana】Prometheus结合Grafana打造智能监控可视化平台
✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,…...
隐私计算实训营:SplitRec:当拆分学习遇上推荐系统
拆分学习的概念 拆分学习的核心思想是拆分网络结构。每一个参与方拥有模型结构的一部分,所有参与方的模型合在一起形成一个完整的模型。训练过程中,不同参与方只对本地模型进行正向或者反向传播计算,并将计算结果传递给下一个参与方。多个参…...
存在nginx版本信息泄露(请求头中存在nginx中间件版本信息)
在Nginx的配置文件中,server_tokens指令用于控制Nginx在HTTP响应头中包含的服务器版本信息,默认为true,开启状态。当设置为off时,Nginx将不会在响应头中包含任何服务器版本信息,仅显示“Server: nginx”这一行…...
在js中观察者模式讲解
在JavaScript中,观察者模式(Observer Pattern)是一种设计模式,允许一个对象(被观察者,Subject)维护一个依赖它的对象列表(观察者,Observer),并在它自身状态发生变化时自动通知这些观察者。观察者模式的典型使用场景包括事件系统、数据绑定和实时更新等情况。 一 、…...
java常用面试题-基础知识分享
什么是Java? Java是一种高级编程语言,旨在提供跨平台的解决方案。它是一种面向对象的语言,具有简单、结构化、可移植、可靠、安全等特点。 Java的主要特点是什么? Java的主要特点包括: 简单性:Java的语法…...
iOS——runLoop
什么是runloop RunLoop实际上就是一个对象,这个对象管理了其需要处理的事件和消息,并提供了一个入口函数来执行相应的处理逻辑。线程执行了这个函数后,就会处于这个函数内部的循环中,直到循环结束,函数返回。 RunLoo…...
python: 多模块(.py)中全局变量的导入
文章目录 global关键字可变类型和不可变类型数据的内存地址单模块(单个py文件)的全局变量示例总结 多模块(多个py文件)的全局变量from x import x导入全局变量示例 import x导入全局变量示例 总结 global关键字 global 的作用范围是模块(.py)级别: 当你在一个模块&…...
0基础学习爬虫系列:Python环境搭建
1.背景 当前网络资源更新非常快,然后对应自己感兴趣的内容,每天盯着刷网站又太费时间。我在尝试借助Ai,搭建一套自己知识抓取更新提醒的系统,这样可以用极少的时间,关注到自己感兴趣的信息。 其实,这套逻辑…...
Unity Shader实现简单的各向异性渲染(采用各向异性形式的GGX分布)
目录 准备工作 BRDF部分 Unity部分 代码 实现的效果 参考 最近刚结束GAMES202的学习,准备慢慢过渡到GAMES103。GAMES103的作业框架为Unity,并没有接触过,因此准备先学一点Unity的使用。刚好101和202都是渲染相关的,因此先学习…...
React开源框架之Refine
React Refine 是一个基于 React 的开源框架,它旨在帮助开发者快速构建企业级后台管理系统(Admin Panel)。Refine 是由 Retax 演变而来,它提供了一套完整的解决方案,用于构建 CRUD(创建、读取、更新、删除&a…...
【iOS】——渲染原理与离屏渲染
图像渲染流水线(图像渲染流程) 图像渲染流程大致分为四个部分: Application 应用处理阶段:得到图元Geometry 几何处理阶段:处理图元Rasterization 光栅化阶段:图元转换为像素Pixel 像素处理阶段࿱…...
详解CSS
目录 CSS 语法 引入方式 选择器 标签选择器 类选择器 ID选择器 通配符选择器 复合选择器 常用CSS color font-size border width和height padding 外边距 CSS CSS(Cascading Style Sheet),层叠样式表, ⽤于控制⻚⾯的样式. CSS 能够对⽹⻚中元素位置…...
GetSubtitles终极指南:5分钟掌握智能字幕下载,高效解决观影难题
GetSubtitles终极指南:5分钟掌握智能字幕下载,高效解决观影难题 【免费下载链接】GetSubtitles 一步下载匹配字幕 项目地址: https://gitcode.com/gh_mirrors/ge/GetSubtitles 还在为找不到匹配的字幕而烦恼吗?GetSubtitles是一款强大…...
JEECG-Boot企业级接口防重与并发控制:双引擎保障系统稳定性的实战指南
JEECG-Boot企业级接口防重与并发控制:双引擎保障系统稳定性的实战指南 【免费下载链接】jeecg-boot AI 低代码平台,「低代码 零代码」双模式驱动:低代码一键生成前后端代码,零代码 5 分钟搭建系统,AI Skills 一句话画…...
机器学习原子间势与连续介质模型在柔性InSe扭转双层原子重构研究中的应用
1. 项目概述:当柔性二维材料遇上扭转角在二维材料的世界里,一个简单的“扭转”操作,往往能打开一扇通往新奇物理现象的大门。从魔角石墨烯中发现的超导和关联绝缘态,到过渡金属硫族化合物(TMDs)中的莫尔激子…...
今天不用就过期:Gemini深度研究模式2024Q3权限变更预警——3类高价值功能即将对免费用户关闭
更多请点击: https://intelliparadigm.com 第一章:Gemini深度研究模式的核心价值与权限变更全景 Gemini深度研究模式(Deep Research Mode)是Google面向专业研究者与开发者推出的增强型推理能力范式,其核心价值在于将多…...
【无功优化】基于改进教与学算法的配电网无功优化【IEEE33节点】附Matlab代码
✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、程序设计科研仿真。🍎完整代码获取 定制创新 论文复现点击:Matlab科研工作室👇 关注我领取海量matlab电子书和数学建模资料 dz…...
卖轴承怎么找客户?下游工厂在哪里
卖轴承找客户,本质是找用轴承的下游工厂,核心难点是拿到这些下游厂的名单和联系人。轴承是机械传动的通用基础件,消耗量大、采购频繁,但下游行业分散、各自聚集在不同产业带,如果没有系统盘过下游版图,销售…...
ClamAV更新失败真相:DNS TXT协议与版本兼容性解析
1. 这不是网络连通性问题,而是ClamAV更新机制被误读的典型现场“Can’t query current.cvd.clamav.net”这个报错,几乎每个在Linux服务器上维护过ClamAV的人都见过。它第一次出现时,90%的运维会立刻去ping、curl、telnet current.cvd.clamav.…...
ChatGPT移动端隐私红线报告(2024Q2):麦克风/剪贴板/位置数据采集路径全曝光,3步彻底锁死敏感权限
更多请点击: https://intelliparadigm.com 第一章:ChatGPT移动端隐私红线报告(2024Q2)核心发现与风险定级 高危数据外泄通道实证 本季度对iOS与Android平台主流ChatGPT客户端(含官方App v6.12.1及第三方封装SDK集成应…...
Gofile极速下载器:Python多线程并发下载的完整实现指南
Gofile极速下载器:Python多线程并发下载的完整实现指南 【免费下载链接】gofile-downloader Download files from https://gofile.io 项目地址: https://gitcode.com/gh_mirrors/go/gofile-downloader Gofile作为流行的文件共享平台,其官方下载机…...
Wireshark实战识别与防御ARP欺骗攻击
1. 为什么ARP欺骗不是“黑客电影”里的特效,而是你每天都在裸奔的真实风险 很多人第一次听说ARP欺骗,是在某部电影里看到主角敲几行命令,对面电脑就突然断网、弹出奇怪窗口、甚至开始自动转账——然后心里一紧:“这玩意儿真能这么…...
