【问题标题】:jQuery .live() vs .on() method for adding a click event after loading dynamic htmljQuery .live() 与 .on() 方法在加载动态 html 后添加点击事件
【发布时间】:2012-02-03 20:34:05
【问题描述】:

我正在使用 jQuery v.1.7.1,其中 .live() 方法显然已被弃用。

我遇到的问题是,当使用以下方法将 html 动态加载到元素中时:

$('#parent').load("http://..."); 

如果我之后尝试添加点击事件,它不会使用以下任何一种方法注册事件:

$('#parent').click(function() ...); 

// according to documentation this should be used instead of .live()
$('#child').on('click', function() ...); 

实现此功能的正确方法是什么?它似乎只适用于 .live() 对我来说,但我不应该使用这种方法。请注意,#child 是一个动态加载的元素。

谢谢。

【问题讨论】:

  • 你为什么说"supposedly deprecated"?你不相信文档吗?
  • 它没有应该被弃用:它弃用。如果您查看jQuery doco for .live(),它会告诉您如何重写.live() 的现有用法以使用.delegate().on()(取决于您是否使用1.7+ 版本)。请注意,如果您添加一个带有.click()“之后”的处理程序,即在动态加载元素之后,它应该可以工作 - 唯一的问题是尝试使用.click() before 动态分配加载元素。
  • 我将措辞改为“显然”,因为这基本上就是我的意思。无论如何,我现在明白了,显然由于 .load() 事件是异步的,那么 #child 元素只能在成功处理程序中被可靠地识别,这是有道理的。

标签: javascript jquery events dom handler


【解决方案1】:

如果您希望点击处理程序适用于动态加载的元素,那么您将事件处理程序设置在父对象上(不会动态加载)并为其提供与您的动态对象匹配的选择器,如下所示:

$('#parent').on("click", "#child", function() {});

事件处理程序将附加到#parent 对象,并且任何时候出现源自#child 的点击事件,它都会触发您的点击处理程序。这称为委托事件处理(事件处理委托给父对象)。

这样做是因为即使#child 对象尚不存在,您也可以将事件附加到#parent 对象,但是当它稍后存在并被点击时,点击事件将冒泡到@ 987654327@ 对象,它将看到它起源于 #child 并且有一个事件处理程序用于单击 #child 并触发您的事件。

【讨论】:

  • 太棒了的解释!我以前从来没有想过live() vs.on(),但今晚我决定再次尝试,你的解释立即揭示了我一直错过的东西。谢谢!
  • 一百万次。在我意识到这在 jQuery 中对于动态创建的孩子来说是可能的之前,我开始使用淘汰赛,非常感谢。
  • 你应该考虑写一本书或其他东西:你的小文字对我的帮助比 jQuery 文档中关于 «on()» 的整页更有帮助。 非常感谢!
  • @jfriend00 您是否知道我们如何将相同的过程应用于悬停、非悬停情况?有没有关于这个的消息来源?
  • @blackhawk - 见this answer。您可以注册mouseentermouseleave 事件并在处理程序中测试触发了哪个事件。 jQuery 的伪“悬停”事件不适用于委托。
【解决方案2】:

试试这个:

$('#parent').on('click', '#child', function() {
    // Code
});

来自$.on() 文档:

事件处理程序仅绑定到当前选定的元素;他们 在您的代码调用 .on() 时,该页面上必须存在。

当您在其上调用$.on() 时,您的#child 元素不存在,因此该事件未绑定(与$.live() 不同)。 #parent,然而,确实存在,所以将事件绑定到它就可以了。

上面代码中的第二个参数充当“过滤器”,仅当事件从#child 冒泡到#parent 时才会触发。

【讨论】:

  • 如果我在 $.load() 方法之后调用 $.on() 方法,那为什么此时 #child 元素不存在?
  • @SeanThoman - 您必须从 .load() 方法的成功处理程序中调用它 - 而不是从 .load() 方法之后的代码中调用它。 #child 仅在成功处理程序实际执行时才被加载,而不是之前加载。
  • 即使如此,将获得的任何数据插入 DOM 所花费的时间也意味着它可能无法连接。我最近做了很多单页应用程序工作,我的标准是 var $body = $('body'); $body.on("event", ".element/#class", function(e){});一切。 1个选择器。无需担心已加载或未加载的内容。
【解决方案3】:

$(document).on('click', '.selector', function() { /* do stuff */ });

编辑:我提供了更多有关其工作原理的信息,因为...单词。 在此示例中,您将在整个文档上放置一个侦听器。

当您在与.selector 匹配的任何元素上click 时,事件会冒泡到主文档——只要没有其他侦听器调用event.stopPropagation() 方法——这将超过冒泡父元素的事件。

您正在侦听来自与指定选择器匹配的元素的任何事件,而不是绑定到特定元素或元素集。这意味着您可以一次创建一个侦听器,该侦听器将自动匹配当前存在的元素以及任何动态添加的元素。

这很聪明有几个原因,包括性能和内存利用率(在大型应用程序中)

编辑:

显然,您可以监听的最接近的父元素会更好,并且您可以使用任何元素代替 document,只要您要监视事件的子元素在该父元素内...与问题无关。

【讨论】:

  • 他试过$(element).on(...)。这是$(document).on(...,element,...)。不同的野兽。
  • @ArnoldRoa 是的,性能更好。您不会在多个子节点上设置监听器,在任何修改 DOM 时都不必重新应用监听器,并且默认情况下事件会通过 DOM 冒泡。运行一次,每个匹配选择器的子元素在点击时都会触发给定的函数。
  • @L422Y 在这里的评论非常具有误导性。如果您对性能影响感到好奇,请查看@jfriend00's comment on @Jared's answer
  • @GustvandeWal 它是如何误导的?如果你去发出一百个 $(this).on(...) 与一次在父元素上监听一个事件相比,它的性能要高得多。
  • 您只是在谈论附加事件。现实世界的性能瓶颈是太多的监听器触发(比如你委托的监听器),而不是需要附加事件的大量元素。
【解决方案4】:

1.7 中 .live() 的等效项如下所示:

$(document).on('click', '#child', function() ...); 

基本上,查看文档中的点击事件并为#child 过滤它们。

【讨论】:

  • 因为这是事件处理程序附加到文档的方式(.live() 的方式)。
  • 现在不推荐使用.live() 的一个原因是将所有实时事件处理程序放在文档对象上是不好的。事情可以真的,真的慢下来。不仅事件必须一直冒泡到文档,而且您可能有很多事件处理程序需要查看文档对象。 .on() 的主要优点是您可以将其附加到更接近实际对象的父对象并大大提高性能。所以......我不建议将.on() 与文档对象一起使用。选择更接近的父对象要好得多。
  • 感谢您的澄清。值得一提的是,事件的性能已经通过 on() 得到了很大的改善,因此它应该比以前少了一个问题。如果附加到父级,我会假设它必须是文档就绪的父级,否则您会看到类似的问题。
  • 在最坏的情况下,这确实模拟了已弃用的.live() 方法;然而,控制委派的能力肯定是有利的。
【解决方案5】:

我知道答案有点晚了,但我已经为 .live() 方法创建了一个 polyfill。我已经在 jQuery 1.11 中对其进行了测试,它似乎工作得很好。我知道我们应该尽可能实现 .on() 方法,但在大型项目中,无论出于何种原因,都无法将所有 .live() 调用转换为等效的 .on() 调用,以下可能工作:

if(jQuery && !jQuery.fn.live) {
    jQuery.fn.live = function(evt, func) {
        $('body').on(evt, this.selector, func);
    }
}

只需在加载 jQuery 之后调用 live() 之前包含它。

【讨论】:

    【解决方案6】:

    .on() 适用于 jQuery 1.7 及更高版本。如果您有旧版本,请使用:

    $("#SomeId").live("click",function(){
        //do stuff;
    });
    

    【讨论】:

    • OP 说“我正在使用 jQuery v.1.7.1”
    • @jfriend--为什么不发布你自己的答案而不是反对我的答案?我每天都使用 live() 与所有低于 1.6 的版本,它工作正常。我可以看到你擅长阅读文档,但有时对一个人来说,将某些东西付诸实践更有帮助。 .live() 有效。期间。
    • @MatthewPatrickCashatt - 我确实发布了我自己的答案,并没有对你的答案投反对票 - 不要做出这种盲目的假设。在 1.7 之前,.delegate() 的性能比 .live() 好得多,这就是 jQuery 文档推荐它并弃用 .live() 的原因。是的,.live() 仍然有效,但这里的答案应该推荐更好的做事方式。我已经在 SO 上看到了 20 次。如果您在 SO 上使用.live() 发布代码,它会被否决(通常不会被我投票,除非它有其他严重问题)。
    • 我没有投反对票,但尽管 .live() 即使在 1.7 版中也确实有效,但您仍应使用 .delegate().on(),因为有充分的理由不推荐使用 .live()。只要您注意这两个较新函数的语法变化,任何一个都可以正常工作。
    • @jfriend00- 你说得对。漫长的一天。我很抱歉。
    【解决方案7】:

    我在项目中使用了“live”,但我的一位朋友建议我应该使用“on”而不是 live。 当我尝试使用它时,我遇到了像你一样的问题。

    在我的页面上,我动态创建按钮表行和许多 dom 内容。但是当我使用时魔法消失了。

    像孩子一样使用它的其他解决方案只是在每次点击时调用您的函数。 但我找到了让它再次发生的方法,这就是解决方案。

    把你的代码写成:

    function caller(){
        $('.ObjectYouWntToCall').on("click", function() {...magic...});
    }
    

    调用 caller();在这样的页面中创建对象之后。

    $('<dom class="ObjectYouWntToCall">bla... bla...<dom>').appendTo("#whereeveryouwant");
    caller();
    

    通过这种方式,您的函数在不应该每次点击页面时都会被调用。

    【讨论】:

      猜你喜欢
      • 2021-02-07
      • 2019-11-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-26
      • 1970-01-01
      相关资源
      最近更新 更多