新闻详情

新闻详情

首页 / 资讯中心 / 详情

30 Seconds of Code:在 JavaScript 中安全地添加与移除事件监听器(on / off 完整实现)

发布时间:2026/10/1 2:37:38来源:尧图网络
30 Seconds of Code:在 JavaScript 中安全地添加与移除事件监听器(on / off 完整实现)
教程文档【免费下载链接】30-seconds-of-codeCoding articles to level up your development skills项目地址https://gitcode.com/gh_mirrors/30/30-seconds-of-code点击查看免费下载事件监听器是浏览器端 JavaScript 交互的核心机制。本指南基于 30 Seconds of Code 仓库中的add-remove-event-listener文档系统讲解如何用EventTarget.addEventListener()与EventTarget.removeEventListener()封装可复用的on/off工具函数并深入解析事件委托event delegation、捕获capturing与options配置的底层原理。读完本文你将掌握一套兼容 jQuery 式调用习惯、零依赖的原生事件绑定/解绑方案以及解决同一个处理器、多个元素等常见场景的进阶模式。为什么需要封装on/off浏览器原生提供了EventTarget.addEventListener()和EventTarget.removeEventListener()两个 API分别用于给元素添加和移除事件监听器。它们本身足够强大但日常开发中存在两个痛点代码冗长每次都要写el.addEventListener(...)且添加与移除时参数必须完全一致容易出错性能与可维护性为大量同质元素逐个绑定监听器会造成性能损耗而 jQuery 时代的$(el).on(...)/$(el).off(...)虽然好用却要为一个小功能引入整个库。仓库中 add-remove-event-listener.md 给出的方案是用两个纯函数封装原生 API并原生支持事件委托从而以最小成本获得 jQuery 式的书写体验。用on函数添加事件监听器EventTarget.addEventListener()的签名是el.addEventListener(type, listener, options);其中options既可以是布尔值true表示捕获阶段执行也可以是一个配置对象包含capture、once、passive等属性。在此基础上仓库的on函数在元素、事件类型和回调之外额外接收一个opts配置对象用来承载事件委托目标与原生 options两层语义const on (el, evt, fn, opts {}) { const delegatorFn e e.target.matches(opts.target) fn.call(e.target, e); el.addEventListener( evt, opts.target ? delegatorFn : fn, opts.options || false ); if (opts.target) return delegatorFn; };逐行拆解on的实现opts.target事件委托的匹配选择器。当提供了target一个 CSS 选择器字符串时函数会创建delegatorFn它先调用e.target.matches(opts.target)判断真正触发事件的目标元素是否匹配该选择器匹配时才用fn.call(e.target, e)执行回调——call的作用是让回调内部的this指向事件目标元素本身与 jQuery 行为一致。opts.options透传给原生 API 的配置。它会被嵌套进opts原样传给addEventListener()。这样once、passive、capture等能力都可以继续使用而无需改变on的调用形态。返回值委托函数引用。当使用了opts.target时on返回delegatorFn。这一设计非常关键——因为真正绑定到元素上的监听器是delegatorFn而非用户传入的fn只有拿到这个引用后续才能通过removeEventListener把它解绑详见下文off的用法。四种典型调用场景const fn () console.log(!); on(document.body, click, fn); // 点击 body 元素时输出 ! on(document.body, click, fn, { target: p }); // 点击 body 下任一 p 元素时输出 !事件委托 on(document.body, click, fn, { options: true }); // 点击 body 时输出 !但使用捕获阶段而非冒泡阶段 on(document.body, click, fn, { target: p, options: { once: true } }); // 点击 body 下的 p 元素时输出 !且仅触发一次注意第四种用法把opts.options设成了对象{ once: true }它会被原样传给addEventListener()从而只执行一次——这正是仓库另一篇文档 event-listener-once.md 所介绍的once标志的直接运用。事件委托为什么把监听器挂在父元素上on的委托能力建立在浏览器的事件传播机制之上。仓库文档 event-bubbling-capturing-delegation.md 详细说明了事件传播的三阶段模型捕获阶段capture phase事件从Window出发经Document、根元素一路下行到目标元素的祖先目标阶段target phase事件在真正被点击的目标元素上触发冒泡阶段bubble phase事件再从目标元素逐级上冒回Window。默认情况下事件走冒泡阶段因此把监听器挂到父元素甚至Window上子元素的事件照样能被捕获到。事件委托因此带来两个明确收益性能提升为大量同类元素如表格中成百上千行只绑定一个监听器而不是逐个绑定显著减少监听器数量动态元素友好之后新增到 DOM 中的子元素无需再注册监听器天然被父级委托覆盖。在on中e.target.matches(opts.target)承担了由父元素判断事件是否来自我们关心的子元素这一职责。仓库中 listen-click-outside-event.md 展示了同类思路的另一变体把监听器委托到document上再用element.contains(e.target)判断点击是否落在元素外部。用off函数移除事件监听器EventTarget.removeEventListener()的签名与addEventListener()一致移除时传入的参数必须与添加时完全相同尤其是监听器函数引用否则移除会静默失败。仓库的off函数刻意保持了与on一致的签名const off (el, evt, fn, opts false) el.removeEventListener(evt, fn, opts);三种移除场景const fn () console.log(!); // 场景一直接解绑原生监听器 document.body.addEventListener(click, fn); off(document.body, click, fn); // 再次点击页面不再输出 ! // 场景二解绑带委托的监听器利用 on 的返回值 const delegatorFn on(document.body, click, fn, { target: p }); off(document.body, click, delegatorFn); // 再次点击 body 下的 p 元素不再输出 ! // 场景三解绑使用捕获阶段的监听器 const delegatorFnCapturing on(document.body, click, fn, { options: true }); off(document.body, click, delegatorFnCapturing, { options: true }); // 捕获阶段的监听器被移除不再输出 !场景二揭示了on返回delegatorFn的必要性委托场景下真正绑定的是包装后的函数用户必须通过返回值拿到它才能完成解绑。场景三则说明opts的options此处为布尔值true等价于{ capture: true }在移除时必须原样传回因为捕获与冒泡阶段视为不同的注册参数不一致就无法命中同一注册项。与 jQuery 的对比与定位仓库文档在 Notes 中明确说明on/off的设计模仿了 jQuery 的on()与off()方法但并非替代品而是让开发者在不引入 jQuery 的前提下获得类似的语法体验。两者最直观的对应关系如下能力jQuery本文方案绑定事件$(el).on(click, fn)on(el, click, fn)事件委托$(el).on(click, .child, fn)on(el, click, fn, { target: .child })解绑事件$(el).off(click, fn)off(el, click, fn)this指向事件目标元素fn.call(e.target, e)保证指向目标元素原生 options支持通过opts.options透传从实现看on/off是完全自包含的纯函数不依赖任何库可原样复制进任何浏览器项目。需要注意的是e.target.matches()要求传入合法的 CSS 选择器字符串且EventTargetAPI 本身是较新的标准不支持旧版 Internet Explorer若需兼容老浏览器应参考 event-listener-once.md 中提供的基于标志位flag的降级写法思路。进阶options的完整能力opts.options透传的是addEventListener()的第三参其完整能力包括capture布尔值true时在捕获阶段触发。on的布尔形式{ options: true }等价于{ capture: true }。捕获阶段由外向内适合先拦截后处理的场景。once布尔值监听器最多触发一次触发后自动移除。现代浏览器原生支持仓库文档 event-listener-once.md 给出了{ once: true }的标准用法以及面向老浏览器的 flag 实现。passive布尔值声明监听器不会调用preventDefault()浏览器可跳过事件队列做优化。仓库文档 passive-scroll-listener-performance.md 专门用它优化scroll监听器避免高频滚动事件成为性能瓶颈。signalAbortSignal传入一个AbortSignal可在信号中止时自动移除监听器。进阶多元素与多事件的批量管理单元素的绑定/解绑之外仓库还提供了两个直接相关的配套工具可与on/off形成完整的事件管理矩阵同一监听器批量绑到多个元素add-remove-event-listener-multiple-elements.md 用Array.prototype.forEach()遍历targets逐一绑定/解绑例如对document.querySelectorAll(a)批量处理点击事件同一元素绑定多个事件类型add-remove-multiple-event-listeners-single-element.md 将事件类型数组传入一次挂载/卸载如[click, mousedown]的多个监听器。这两个工具与本文的on/off组合使用可以覆盖单元素单事件含委托→ 多元素 → 多事件的全部日常场景。若要进一步模拟 jQuery 的触发能力仓库的 trigger-event.md 还提供了基于CustomEvent的triggerEvent实现可与on搭配完成完整的事件生命周期管理。小结添加监听器用on(el, evt, fn, opts)opts.target开启事件委托、opts.options透传原生配置、返回值为委托函数引用移除监听器用off(el, evt, fn, opts)参数必须与添加时完全一致委托场景务必使用on的返回值事件委托基于冒泡机制兼顾性能与动态元素场景捕获/冒泡阶段的选择通过options控制整套实现零依赖、纯函数、可复制是 jQuery 事件 API 的轻量原生替代完整的可运行示例见仓库文档 add-remove-event-listener.md。赞分享教程文档【免费下载链接】30-seconds-of-codeCoding articles to level up your development skills项目地址https://gitcode.com/gh_mirrors/30/30-seconds-of-code点击查看免费下载相关推荐YouTube.js 解析引擎深度解析Heatmap 热度图节点类及其在视频观看页中的应用YouTube.js 解析引擎深度解析Heatmap 热度图节点类及其在视频观看页中的应用 导读 Heatmap 是 YouTube.jsInnerTube教程文档终极JavaScript URL操作指南掌握30-seconds-of-code的高效技巧终极JavaScript URL操作指南掌握30 seconds of code的高效技巧 30 seconds of code是一个基于JavaScript教程文档rsuite DOMHelper 事件绑定实战on/off 方法与可撤销监听器完全指南rsuite DOMHelper 事件绑定实战on/off 方法与可撤销监听器完全指南 在 React 应用中官方推荐通过声明式的事件绑定如 onClic前端UI组件上一篇革命性iOS激活锁绕过applera1n一站式解决方案深度解析下一篇终极宝可梦随机化教程Universal Pokemon Randomizer ZX完全指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

UE5预测IK实战:从Foot IK踩坑到动画修改器与ALS整合 2026/10/1 9:27:21

UE5预测IK实战:从Foot IK踩坑到动画修改器与ALS整合

1. 从“做不出来”说起:预测IK到底卡在哪做角色动画这行的,尤其是碰过UE5的,大概率都经历过这样一个阶段:看别人演示的脚部IK贴合地面,角色在斜坡上走得稳稳当当,脚底板严丝合缝地踩在石头台阶上&#xff0…

阅读更多 →
ESXi定制ISO指南:用ESXi-Customizer-PS集成网卡驱动解决No Network Adapters 2026/10/1 9:27:08

ESXi定制ISO指南:用ESXi-Customizer-PS集成网卡驱动解决No Network Adapters

如果你玩过ESXi,大概率遇到过这种尴尬:镜像已经写进U盘,安装界面跑完引导,结果弹出一句No Network Adapters Found,整个流程直接卡死。我上个月给一台二手工作站装ESXi 8.0就撞上了——板载的Realtek R8125B完全不认&a…

阅读更多 →
PermissionError 报错根治:pip 权限不足与虚拟环境解决方案 2026/10/1 9:27:08

PermissionError 报错根治:pip 权限不足与虚拟环境解决方案

兄弟,看到PermissionError: [Errno 13] Permission denied这一行,是不是瞬间头皮发麻?别急,这基本上是每个玩 Python 的人都会碰到的一道坎,尤其是当你满心欢喜地 clone 了一个开源项目,准备用pip install …

阅读更多 →
理解Linux基础命令设计逻辑,掌握文件、进程与网络排查实战 2026/10/1 9:27:08

理解Linux基础命令设计逻辑,掌握文件、进程与网络排查实战

1. 先理解Linux命令的底层设计,再谈记忆命令很多刚接触Linux的朋友,包括我当年刚入职做运维的时候,都走入过一个误区:把Linux命令当成单词表去背。ls是列目录,cd是切换目录,cp是复制,mv是移动&a…

阅读更多 →
MongoDB固定集合(Capped Collection)原理、容量设计与Tailable游标实战指南 2026/10/1 9:26:55

MongoDB固定集合(Capped Collection)原理、容量设计与Tailable游标实战指南

固定集合这个名字,听起来像是 MongoDB 新手阶段练手才会碰的东西,但我个人觉得它恰恰是很多后端老手也会忽略的宝藏特性。最早我是做访问日志模块时真正领会到它的价值:一天上千万条日志,全量保存不可能,定期清理又会让…

阅读更多 →
火电厂DCS改造中控制逻辑组态迁移的实战方法论与避坑指南 2026/10/1 9:26:55

火电厂DCS改造中控制逻辑组态迁移的实战方法论与避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉