草庐IT

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

coder 2023-05-01 原文

这是从哪里来的

当我第一次学习 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/

    有关javascript - 所有 jquery 事件都应该绑定(bind)到 $(document) 吗?的更多相关文章

    1. ruby - 如何以所有可能的方式将字符串拆分为长度最多为 3 的连续子字符串? - 2

      我试图获取一个长度在1到10之间的字符串,并输出将字符串分解为大小为1、2或3的连续子字符串的所有可能方式。例如:输入:123456将整数分割成单个字符,然后继续查找组合。该代码将返回以下所有数组。[1,2,3,4,5,6][12,3,4,5,6][1,23,4,5,6][1,2,34,5,6][1,2,3,45,6][1,2,3,4,56][12,34,5,6][12,3,45,6][12,3,4,56][1,23,45,6][1,2,34,56][1,23,4,56][12,34,56][123,4,5,6][1,234,5,6][1,2,345,6][1,2,3,456][123

    2. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

      为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

    3. ruby - ruby 中的 TOPLEVEL_BINDING 是什么? - 2

      它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput

    4. ruby-on-rails - 跳过状态机方法的所有验证 - 2

      当我的预订模型通过rake任务在状态机上转换时,我试图找出如何跳过对ActiveRecord对象的特定实例的验证。我想在reservation.close时跳过所有验证!叫做。希望调用reservation.close!(:validate=>false)之类的东西。仅供引用,我们正在使用https://github.com/pluginaweek/state_machine用于状态机。这是我的预订模型的示例。classReservation["requested","negotiating","approved"])}state_machine:initial=>'requested

    5. ruby - Nokogiri 剥离所有属性 - 2

      我有这个html标记:我想得到这个:我如何使用Nokogiri做到这一点? 最佳答案 require'nokogiri'doc=Nokogiri::HTML('')您可以通过xpath删除所有属性:doc.xpath('//@*').remove或者,如果您需要做一些更复杂的事情,有时使用以下方法遍历所有元素会更容易:doc.traversedo|node|node.keys.eachdo|attribute|node.deleteattributeendend 关于ruby-Nokog

    6. ruby - 获取模块中定义的所有常量的值 - 2

      我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c

    7. jquery - 我的 jquery AJAX POST 请求无需发送 Authenticity Token (Rails) - 2

      rails中是否有任何规定允许站点的所有AJAXPOST请求在没有authenticity_token的情况下通过?我有一个调用Controller方法的JqueryPOSTajax调用,但我没有在其中放置任何真实性代码,但调用成功。我的ApplicationController确实有'request_forgery_protection'并且我已经改变了config.action_controller.consider_all_requests_local在我的environments/development.rb中为false我还搜索了我的代码以确保我没有重载ajaxSend来发送

    8. java - 我的模型类或其他类中应该有逻辑吗 - 2

      我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

    9. ruby-on-rails - 事件管理员日期过滤器日期格式自定义 - 2

      是否有简单的方法来更改默认ISO格式(yyyy-mm-dd)的ActiveAdmin日期过滤器显示格式? 最佳答案 您可以像这样为日期选择器提供额外的选项,而不是覆盖js:=f.input:my_date,as::datepicker,datepicker_options:{dateFormat:"mm/dd/yy"} 关于ruby-on-rails-事件管理员日期过滤器日期格式自定义,我们在StackOverflow上找到一个类似的问题: https://s

    10. ruby-on-rails - 创建 ruby​​ 数据库时惰性符号绑定(bind)失败 - 2

      我正在尝试在Rails上安装ruby​​,到目前为止一切都已安装,但是当我尝试使用rakedb:create创建数据库时,我收到一个奇怪的错误:dyld:lazysymbolbindingfailed:Symbolnotfound:_mysql_get_client_infoReferencedfrom:/Library/Ruby/Gems/1.8/gems/mysql2-0.3.11/lib/mysql2/mysql2.bundleExpectedin:flatnamespacedyld:Symbolnotfound:_mysql_get_client_infoReferencedf

    随机推荐