尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

事件委托实战:用单个监听器为消息列表实现 [x] 关闭按钮

事件委托实战:用单个监听器为消息列表实现 [x] 关闭按钮 文档教程前端【免费下载链接】zh.javascript.info现代 JavaScript 教程The Modern JavaScript Tutorial以最新的 ECMAScript 规范为基准通过简单但足够详细的内容为你讲解从基础到高阶的 JavaScript 相关知识。项目地址https://gitcode.com/gh_mirrors/zh/zh.javascript.info点击查看免费下载本文源自《现代 JavaScript 教程The Modern JavaScript Tutorial》中文仓库 2-ui/2-events/03-event-delegation 章节的实战任务「使用委托隐藏消息」是一份面向初学者的完整解题指南。你将掌握如何在容器上只挂载一个事件监听器通过事件冒泡与event.target识别点击来源从而让列表中每一个[x]移除按钮都正常工作并理解事件委托为何能简化初始化、节省内存且天然适应 DOM 的动态增删。任务回顾让消息列表的移除按钮工作任务文档 task.md 给出了明确要求有一个带有移除按钮[x]的消息列表。让按钮可以工作。 P.S. 在容器上应该只有一个事件监听器请使用事件委托。也就是说最终交付的代码必须满足一个硬性约束不能为每个[x]按钮分别绑定onclick而要在它们的共同祖先消息容器上注册唯一一个监听器借助事件冒泡机制完成对任意按钮的响应。起始 HTML 结构三个消息面板练习提供的起始文件是 source.view/index.html其 DOM 结构如下篇幅所限省略了正文长段落div idcontainer div classpane h3Horse/h3 p...一段介绍马的文字.../p button classremove-button[x]/button /div div classpane h3Donkey/h3 p.../p button classremove-button[x]/button /div div classpane h3Cat/h3 p.../p button classremove-button[x]/button /div /div script // ...your code... /script结构上是一层清晰的嵌套关系容器#container→ 三个面板.pane→ 每个面板内有一个标题、一段描述和唯一的关闭按钮button.remove-button。起始文件中的script只有一行注释// ...your code...等待你填写实现。配套的样式文件 source.view/messages.css与 solution.view/messages.css 完全相同做了如下安排.pane采用position: relative为内部绝对定位的按钮提供定位基准.remove-button使用position: absolute定位在面板右上角top: 0; right: 10px并显式设置了border: none、background: transparent和cursor: pointer让[x]呈现为干净的可点击文本按钮。为什么不逐个绑定而要使用事件委托本节对应的理论主干是 article.md 中介绍的**事件委托Event Delegation**模式捕获和冒泡允许我们实现最强大的事件处理模式之一即事件委托模式。这个想法是如果我们有许多以类似方式处理的元素那么就不必为每个元素分配一个处理程序 —— 而是将单个处理程序放在它们的共同祖先上。在这个练习里面板数量是 3如果是真实产品场景可能是 30、300 甚至动态渲染的任意数量。逐个绑定的做法有三个明显弊端初始化代码膨胀需要querySelectorAll遍历所有按钮再逐个addEventListener内存占用随元素数量线性增长每个按钮都持有一个独立的处理函数引用无法覆盖未来新增的元素用innerHTML批量插入新消息后新按钮不会自动获得事件处理。事件委托通过「在共同祖先#container上放一个处理程序在处理程序中检查event.target」的算法见 article.md 总结一节一次性解决了上述全部问题。标准解法container.onclick 单监听器练习的参考答案完整实现位于 solution.view/index.html核心代码只有四行container.onclick function(event) { if (event.target.className ! remove-button) return; let pane event.target.closest(.pane); pane.remove(); };逐行拆解这段代码的执行逻辑container.onclick function(event) { ... }把唯一一个点击监听器挂在容器#container上。由于点击事件默认沿「目标 → 祖先」方向冒泡面板内任意位置的点击最终都会到达容器因此这里能捕获所有按钮点击。这正是任务要求的「在容器上应该只有一个事件监听器」。if (event.target.className ! remove-button) return;委托处理程序的关键一步是校验事件源。event.target指向实际被点击的元素即冒泡链的起点。如果它不是一个classremove-button的按钮——比如点击了消息的标题h3或正文p——就直接return不做任何处理。只有当点击确实落在[x]按钮上时后续逻辑才会执行。let pane event.target.closest(.pane);closest(selector)从当前元素自身开始向上查找最近的匹配祖先。这里从被点击的按钮出发向上找到包裹它的消息面板.pane。之所以不用event.target.parentNode之类的直接父级写法是因为closest更稳健即使将来按钮被嵌套进更多层级例如外面包一层图标容器closest(.pane)依然能正确找到面板。pane.remove()直接移除整个.pane元素。现代浏览器原生支持Element.remove()无需先拿到父节点再removeChild代码更简洁。执行效果点击任意消息右上角的[x]对应的整条消息面板会从页面中消失其余面板不受影响。注意 event.target 的细节点击可能发生在子元素上在主章节 article.md 的八卦图示例中作者特别强调了一个委托实现中的常见坑点击可能不是发生在td上而是发生在其内部——当单元格里嵌套了strong、em等标签时event.target会是那个最内层的元素而不是你关心的目标元素。在本练习中[x]按钮内部没有嵌套标签event.target恰好就是按钮本身因此event.target.className ! remove-button的判断是成立的。但如果你把按钮内容改成button classremove-buttonspan[x]/span/button点击[x]文字时event.target会变成span此时className判断就会失效。稳健的写法是仿照主章节的改进版代码用closest从源元素向上寻找目标container.onclick function(event) { let button event.target.closest(.remove-button); if (!button) return; // 点击不在任何移除按钮上 if (!container.contains(button)) return; // 防止嵌套容器误判本练习可省略 button.closest(.pane).remove(); };主章节 article.md 给出的closest三步检查法找祖先 → 判空返回 → 用contains排除嵌套表格中的别人家的 td是事件委托处理嵌套 DOM 时的通用防御性写法值得在更复杂的真实场景中套用。从任务出发理解事件委托的三步算法完成这个练习后可以把它抽象为 article.md 总结中的通用算法在容器上放一个处理程序——本练习中是#container在处理程序中检查源元素event.target——本练习中是判断className是否为remove-button如果事件发生在我们感兴趣的元素内就处理该事件——本练习中是移除对应的.pane。委托带来的收益对应本练习的实际体验简化初始化并节省内存只需注册一个监听器而不是三个或任意数量更少的代码新增/删除消息面板时无需同步增删处理程序DOM 批量修改友好即使用innerHTML一次性重绘整个列表委托依然生效。同时也要记住它的两个固有局限详见 article.md事件必须能冒泡才可被委托另外低层处理程序不应调用event.stopPropagation()阻断冒泡容器级处理程序会对容器内任意位置的点击都产生响应即使你并不关心会带来少量可忽略不计的 CPU 开销。延伸同一模式的更多应用这个练习展示的「单监听器 data 标记 统一分派」思路在主章节 article.md 中还延伸出了两个经典变体与本任务同源可以一并体会标记中的行为Action in Markup菜单按钮通过data-actionsave声明自己的动作容器处理程序读取event.target.dataset.action后调用对象上对应的方法HTML 结构可随时增删按钮而无需改动 JS。行为模式Behavior Pattern用data-counter、data-toggle-id等特性以声明方式给任意元素附加行为由document级处理程序统一分发注意给document挂监听器时必须用addEventListener避免document.onclick ...相互覆盖。小结「使用委托隐藏消息」是事件委托章节的入门级实战任务它在#container上注册唯一一个click监听器通过校验event.target.className识别[x]按钮再用closest(.pane)定位待移除的面板并调用remove()完成删除。完整可运行的参考实现见 solution.view/index.html起始模板见 source.view/index.html。掌握了这一模式你就能以近乎零成本的方式为任意数量的同类元素提供统一的事件处理这也是 DOM 编程中最值得优先掌握的技能之一。赞分享文档教程前端【免费下载链接】zh.javascript.info现代 JavaScript 教程The Modern JavaScript Tutorial以最新的 ECMAScript 规范为基准通过简单但足够详细的内容为你讲解从基础到高阶的 JavaScript 相关知识。项目地址https://gitcode.com/gh_mirrors/zh/zh.javascript.info点击查看免费下载相关推荐现代 JavaScript 教程用事件委托Event Delegation实现消息列表的 [x] 关闭按钮现代 JavaScript 教程用事件委托Event Delegation实现消息列表的 x 关闭按钮 本文围绕《现代 JavaScript 教程》en文档/教程前端JavaScript 事件处理实战为消息列表添加关闭按钮Modern JavaScript TutorialJavaScript 事件处理实战为消息列表添加关闭按钮Modern JavaScript Tutorial 本文基于 Modern JavaScript文档/教程前端Modern JavaScript Tutorial 实战为消息面板添加关闭按钮insertAdjacentHTML 与事件处理器Modern JavaScript Tutorial 实战为消息面板添加关闭按钮insertAdjacentHTML 与事件处理器 本篇文章围绕 Mode文档/教程前端上一篇Linux新手必看LinuxCommandLibrary如何让你7天入门终端命令下一篇5分钟掌握Windows智能散热FanControl终极风扇控制指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表