为了账号安全,请及时绑定邮箱和手机立即绑定

掌握JavaScript事件委托技巧

在现代的 JavaScript 开发中,事件处理对于让 web 应用程序变得互动和动态至关重要。随着应用规模的扩大,管理事件监听器的复杂性也会随之增加。此时出现了 事件委托 这一概念,它是一种利用 JavaScript 的 事件冒泡 机制来优化事件处理的强大模式。

事件委托是什么?

事件委托是一种技巧或方法,你只需将一个事件监听器附加到父元素,以管理子元素上的事件。而不是为每个子元素分别添加监听器,父元素捕获冒泡事件并确定事件源。

它是怎么运作呢?

事件委托基于两种关键的 JavaScript 机制。

  • 冒泡事件: 事件从目标元素冒泡到 DOM 树的根节点。

  • event.target: 标识事件源元素。
事件委托的优点
特性 解释
性能 减少事件监听器的数量,节约内存并提高效率。
控制机制 自动管理动态添加的元素,不再需要额外的监听器。
内存处理 在代码中较少的位置集中处理事件逻辑。
常见用例 在现代浏览器中广泛支持。
深入探讨事件冒泡机制

JavaScript中的事件会遵循一个可预测的生命周期在DOM中。理解这些阶段对于掌握委托技巧至关重要:

1.捕获阶段: 事件从根节点开始,遍历至目标元素。
2.目标阶段: 事件在目标元素上触发。
3.冒泡阶段: 事件向上冒泡到根节点,从目标元素开始。

事件委托主要在冒泡阶段生效。

实际代码示例:事件代理的实战应用

场景1:处理列表项的点击事件
不是为每个列表项添加监听器,而是:

    const ul = document.querySelector("ul");
    ul.addEventListener("click", (event) => {
        if (event.target.tagName === "LI") {
            console.log("控制台输出点击的项目:", event.target.textContent);
        }
    });

点全屏/退出全屏

这个单一的监听器管理所有的li元素,甚至那些动态添加的也不例外。

    const ul = document.querySelector("ul");
    ul.innerHTML += "<li>新项目项</li>"; // 不需要新增监听器;

进入全屏,退出全屏

场景2:
结合事件委托与多种事件类型的检查:

    document.querySelector("#container").addEventListener("click", (event) => {
        if (event.target.matches(".button")) {
            console.log("点击了按钮");
        } else if (event.target.matches(".link")) {
            console.log("点击了链接");
        }
    });

全屏模式,退出全屏

情景3:处理带有委派的表单操作

    document.querySelector("#form").addEventListener("input", (event) => {
        if (event.target.matches("input[name='email']")) {
            console.log("邮箱更新了:", event.target.value);
        } else if (event.target.matches("input[name='password']")) {
            console.log("密码更新了.");
        }
    });

进入全屏,退出全屏

这种方法确保任何动态添加的新的输入框都能自动处理。

事件委托的实用技巧

1. 使用具体的选择器: 避免使用过于宽泛的匹配,以防止意外行为。可以使用 event.target.matches()event.target.closest() 方法。
2. 避免过度委派: 如果父元素包含大量子元素,将过多的事件委派给父元素可能会导致效率变低。
3. 合理安排条件: 结构化你的条件以最小化不必要的检查。
4. 节流或防抖事件: 对于像 scrollresize 这样的事件,可以通过节流来提高性能:

    // 节流函数,限制回调函数的执行频率
    function throttle(callback, delay) {
        let lastTime = 0;
        return function (...args) {
            const now = Date.now();
            if (now - lastTime >= delay) {
                callback(...args);
                lastTime = now;
            }
        };
    }
    // 当滚动时,每隔200毫秒打印"Scrolled!"
    document.addEventListener("scroll", throttle(() => console.log("Scrolled!"), 200));

全屏模式 退出全屏

事件委托(将事件处理任务委派给其他对象)与直接处理事件
方面 直接事件处理 事件委托
设置复杂性 需要多个监听器。 单个监听器处理多个事件。
动态元素 需要手动重新绑定。 自动支持。
大型DOM下的性能表现 监听器数量增加时性能会下降。 集中式监听器更高效。
可维护性 逻辑分散在多个地方,难以维护。 集中且整洁。
在框架中的事件委托

React
虽然 React 抽象了 DOM 操作的过程,你可以在合成事件中看到类似委托的效果。React 使用一个根监听器来监听和处理其虚拟 DOM 中的所有事件。

jQuery,jQuery的.on()方法简化了事件委托处理。

    $(document).on("click", ".dynamic-button", function () {
        console.log("按钮被点了:", $(this).data("id"));
    });

全屏显示 退出全屏

事件委托中的常见问题

1.意外匹配
确保你的选择器不会意外地选中无关的元素,可以使用具体的选择器,或者使用 event.target.closest() 方法。

2.防止事件冒泡
有时,你可能需要阻止特定元素的事件冒泡。

    document.querySelector("#container").addEventListener("click", (event) => {
        if (event.target.matches(".prevent-bubble")) {
            event.stopPropagation();
        }
    });
    document.querySelector("#container").addEventListener("click", (event) => {
        if (event.target.matches(".prevent-bubble")) {
            event.stopPropagation();
        }
    });

In this context, the original code is kept as-is because the technical terms and syntax are universally recognized and do not have direct Chinese translations that are commonly used. Hence, the code remains untranslated.

全屏, 退出全屏

性能考量

1.基准点
事件代理能够减少大型DOM中的内存使用,但如果父元素处理了太多事件,则可能会导致延迟。

2.开发者工具
使用浏览器开发者工具(如Chrome控制台中的getEventListeners)查看附加的事件监听器。

获取事件监听器(document.querySelector("#parent"))

全屏显示 退出全屏

小技巧
  • 模拟非冒泡事件中的委托处理: 一些事件,如focusblur没有冒泡行为。建议使用例如focusinfocusout代替。
    document.addEventListener("focusin", (event) => {
        console.log("得到了焦点:", event.target);
    });

全屏查看,退出全屏

  • 在根级别附加监听器: 为了最大程度的灵活性,在单页应用 (SPA) 或动态内容中,将监听器附加到文档(document)。
结尾:

JavaScript 事件代理 是一种关键的优化策略,能够高效地适应扩展交互式应用程序。通过将事件处理集中在一处、减少内存占用并提高维护性,它使开发人员能够构建稳健且高性能的 web 应用。

以下为分割线

我的主页:https://shafayet.zya.me


给你个梗(可能你会觉得超有共鸣)^^^^

这是一张图片

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消