javascript - 所有 jquery 事件都应该绑定(bind)到 $(document) 吗?

标签 javascript jquery jquery-selectors jquery-on

这是从哪里来的

当我第一次学习 jQuery 时,我通常会附加这样的事件:

$('.my-widget a').click(function() {
    $(this).toggleClass('active');
});

在了解了更多关于选择器速度和事件委托(delegate)的知识后,我在几个地方读到“jQuery 事件委托(delegate)将使您的代码更快”。于是我开始写这样的代码:
$('.my-widget').on('click','a',function() {
    $(this).toggleClass('active');
});

这也是复制已弃用的 .live() 事件行为的推荐方法。这对我很重要,因为我的很多网站一直在动态添加/删除小部件。上面的行为并不完全像 .live() ,因为只有添加到现有容器 '.my-widget' 的元素才会获得行为。如果我在该代码运行后动态添加另一个 html 块,这些元素将不会将事件绑定(bind)到它们。像这样:
setTimeout(function() {
    $('body').append('<div class="my-widget"><a>Click does nothing</a></div>');
}, 1000);

我想要达到的目标:
  • .live() 的旧行为//意味着将事件附加到尚不存在的元素
  • .on() 的好处
  • 绑定(bind)事件的最快性能
  • 管理事件的简单方法

  • 我现在附上所有这样的事件:
    $(document).on('click.my-widget-namespace', '.my-widget a', function() {
        $(this).toggleClass('active');
    });
    

    这似乎满足了我的所有目标。 (是的,由于某种原因,它在 IE 中变慢了,不知道为什么?)
    它很快,因为只有一个事件与单个元素相关联,并且辅助选择器仅在事件发生时进行评估(如果这里有错误,请纠正我)。命名空间很棒,因为它可以更轻松地切换事件监听器。

    我的解决方案/问题

    所以我开始认为 jQuery 事件应该总是绑定(bind)到 $(document)。
    你有什么理由不想这样做吗?
    这可以被视为最佳实践吗?如果不是,为什么?


    如果您已阅读全文,谢谢。我感谢任何/所有反馈/见解。

    假设:
  • 使用支持 .on() 的 jQuery//至少版本 1.7
  • 您希望将事件添加到动态添加的内容

  • 读物/例子:
  • http://24ways.org/2011/your-jquery-now-with-less-suck
  • http://brandonaaron.net/blog/2010/03/4/event-delegation-with-jquery
  • http://www.jasonbuckboyer.com/playground/speed/speed.html
  • http://api.jquery.com/on/
  • 最佳答案

    不 - 您不应该将所有委托(delegate)的事件处理程序绑定(bind)到 document对象。这可能是您可以创建的性能最差的场景。

    首先,事件委托(delegate)并不总是能让你的代码更快。在某些情况下,这是有利的,而在某些情况下则不然。当您真正需要事件委托(delegate)并从中受益时,您应该使用事件委托(delegate)。否则,您应该将事件处理程序直接绑定(bind)到发生事件的对象,因为这通常会更有效。

    其次,您不应该在文档级别绑定(bind)所有委托(delegate)事件。这就是为什么.live()已弃用,因为当您以这种方式绑定(bind)大量事件时,这非常低效。对于委托(delegate)事件处理,将它们绑定(bind)到最近的非动态父级会更有效率。

    第三,并非所有事件都有效或所有问题都可以通过委托(delegate)解决。例如,如果您想拦截输入控件上的键事件并阻止将无效键输入到输入控件中,则不能使用委托(delegate)事件处理来做到这一点,因为当事件冒泡到委托(delegate)处理程序时,它已经已由输入控件处理,现在影响该行为为时已晚。

    以下是需要或有利事件委托(delegate)的时候:

  • 当您在其上捕获事件的对象是动态创建/删除的,并且您仍然希望在它们上捕获事件而不必在每次创建新事件处理程序时显式重新绑定(bind)事件处理程序。
  • 当您有很多对象都需要完全相同的事件处理程序时(其中很多至少是数百个)。在这种情况下,在设置时绑定(bind)一个委托(delegate)的事件处理程序可能比数百个或更多的直接事件处理程序更有效。请注意,委托(delegate)事件处理在运行时的效率总是低于直接事件处理程序。
  • 当您 try catch (在文档中的更高级别)发生在文档中任何元素上的事件时。
  • 当您的设计明确使用事件冒泡和 stopPropagation() 来解决页面中的某些问题或功能时。


  • 要进一步理解这一点,需要了解 jQuery 委托(delegate)的事件处理程序是如何工作的。当你调用这样的东西时:
    $("#myParent").on('click', 'button.actionButton', myFn);
    

    它在 #myParent 上安装了一个通用的 jQuery 事件处理程序。对象。当单击事件冒泡到此委托(delegate)事件处理程序时,jQuery 必须检查附加到此对象的委托(delegate)事件处理程序列表,并查看事件的原始元素是否与委托(delegate)事件处理程序中的任何选择器匹配。

    因为选择器可能相当复杂,这意味着 jQuery 必须解析每个选择器,然后将其与原始事件目标的特征进行比较,以查看它是否与每个选择器匹配。这不是一个便宜的操作。如果只有一个选择器也没什么大不了的,但是如果您将所有选择器放在文档对象上并且有数百个选择器要与每个冒泡事件进行比较,这可能会严重影响事件处理性能。

    出于这个原因,您希望设置委托(delegate)的事件处理程序,以便委托(delegate)的事件处理程序尽可能接近目标对象。这意味着更少的事件会通过每个委托(delegate)的事件处理程序冒泡,从而提高性能。将所有委托(delegate)事件放在文档对象上可能是最糟糕的性能,因为所有冒泡事件都必须经过所有委托(delegate)事件处理程序,并针对所有可能的委托(delegate)事件选择器进行评估。这就是为什么.live()已弃用,因为这就是 .live()确实如此,但事实证明它非常低效。

    因此,要实现优化的性能:
  • 只有在实际提供您需要的功能或提高性能时才使用委托(delegate)事件处理。不要总是使用它,因为它很容易,因为当您实际上不需要它时。实际上,它在事件调度时的性能比直接事件绑定(bind)更差。
  • 尽可能将委托(delegate)的事件处理程序附加到离事件源最近的父级。如果您使用委托(delegate)事件处理是因为您有要为其捕获事件的动态元素,则选择最接近的本身不是动态的父级。
  • 为委托(delegate)的事件处理程序使用易于评估的选择器。如果您遵循委托(delegate)事件处理的工作原理,您就会明白委托(delegate)事件处理程序必须多次与大量对象进行比较,因此尽可能选择高效的选择器或向对象添加简单的类以便可以使用更简单的选择器提高委托(delegate)事件处理的性能。
  • 关于javascript - 所有 jquery 事件都应该绑定(bind)到 $(document) 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12824549/

    相关文章:

    jquery - 选择元素的id

    javascript - Twilio.Device.setup 无权访问用户的麦克风?

    javascript - 如何仅在 CSS 中创建具有绝对顶部和底部以及固定边的边框?包括图像

    javascript - fullCalendar renderEvent 不粘连

    jQuery - 运行change()和ready()函数

    jquery - 具有上下文的 jQuery 选择器的性能

    javascript - 通过 PHP 从 HTML 表单向数据库插入多个选项

    Jquery:在父div内的索引处选择子div

    javascript - Ajax不发送数据到php文件

    jquery - 组合多个 css3 选择器