jQuery的.on方法无法工作,但.live可以。

25

由于live()方法已在1.7版本中被弃用,我开始查看我的源代码并将所有的实时事件处理程序转换为on()。我以为这个更改很简单,一切都会像以前一样工作,但是我遇到了一些行为不正常的代码。

我有以下jQuery选择器来绑定table标签的click事件...

$('table.accordion-header').live("click", function ($e) {
  // gobs of code
}

...并且它运行良好(例如-即使在页面上发生异步回发后,我的表格标签点击事件也会被触发)。但是如果我将代码更改为以下内容

$('table.accordion-header').on("click", function ($e) {
  // gobs of code
}

在页面上发生任何异步后台回发后,点击事件将不再被触发。请注意 - 点击事件仅在异步后台回发之前起作用,但在此之后将不再起作用。那么我错过了什么?


请检查您是否将其放在“$(document).ready()”函数类型中,或者您是否在调用它之前并返回false。有一种检查方法:$('table.accordion-header')。trigger('click'); - Guilherme David da Costa
6个回答

54

这样的问题已经被回答过很多次了,因为似乎很常见人们不太理解动态版本的.on()如何工作。你正在使用静态形式的.on(),其中对象必须在调用.on()时存在,而你可能打算使用以下动态形式的.on()

$(someStaticParentObject).on("click", 'table.accordion-header', function ($e) {
  // code
}

.live()被替换为.on(),因为.on()允许您通过指定动态对象的静态父对象来附加事件处理程序,从而实现更好的性能,这比将其附加到document对象更有效率,这就是.live()的作用。我建议您阅读以下先前由我编写的答案,以了解如何最好地使用.on()。这些答案还包括有关如何最有效地使用.on()以及它是如何工作的简要描述的评论:

jquery: on vs live

Does jQuery.on() work for elements that are added after the event handler is created?

How does jQuery's new on() method compare to the live() method in performance?

jQuery.bind()和jQuery.on()有什么区别?

为什么不将JavaScript事件委托发挥到极致?


1
你提到附加到静态元素比文档更好。但是,如果你不知道特定的父级,使用 $('body').on 相对于 $(document).on 有什么优势? - Paul Alexander
@jfriend00,在很多情况下,附加到document是唯一的可能性,因为在加载DOM(页面加载)时没有其他对象存在。 - md1337
@md1337 - 通常情况下,你应该在页面加载完成后设置事件处理程序,而不是在加载之前。在文档上放置大量的事件处理程序会导致运行时效率低下。 - jfriend00
@jfriend00 我正在开发网络应用程序而不是网站。这是不同的世界。你还没有回答我的问题,你可能没有答案!再见。 - md1337
1
@md1337,答案是隐藏控件并在页面加载后使它们出现。 - user871784
显示剩余6条评论

48

等同于

$('table.accordion-header').live("click", function ($e) {
  // gobs of code
} );

is

$(document).on("click", 'table.accordion-header', function ($e) {
  // gobs of code
} );

4
然而,如果您真正理解了.on()的工作原理以及应该如何使用它,那么有比使用$(document).on()更有效的使用方式。.live()被替换的一个主要原因是允许人们比这更有效地使用它。下面的答案提供了更多细节。 - jfriend00
是的,确实如此。我只是在使用OP提供的内容...还有.delegate()可以更精细地控制... - Gabriele Petrioli
如果您正在使用元素的ID进行单击操作,请将“#”添加到语法中:$(document).on("click", '#id_of_the_element', function ($e) { // 大量代码 }); - Adrian P.

0

我能说的最好的方式就像jQuery上的文档所说的那样,关于.live().on()功能:

  1. 在你的选择器"$(selector)"中加入一个随页面一起加载的具体元素 - 而不是动态的。
  2. 然后将次要选择器放入方法中,其中指示了"selector" - 这个可以是动态创建的。
//so this..
    $('table.accordion-header').live("click", function ($e) {
  // gobs of code
});

//becomes this..   
    $('table').on("click",'.accordion-header', function ($e) {
  // gobs of code
});

假设“table”已经加载到页面中。

0

在浪费了大量时间后,我发现我的页面上实际上有两个搜索表单,它们都使用相同的ID。

解决方案是给表单添加一个类名,这样我就可以集体地针对它们并使用.each()来逐个地定位它们。


0

我也试着将我的live()更新为on(),但一直遇到困难,后来有人向我展示了第一个父级或上下文选择器的工作原理,最终搞定了。关键是确保这个第一个元素在文档对象模型中。

$(this)与 .on() 的工作方式也不是很明显。

$(document).on("click", 'table.accordion-header', function ($e) {
  // gobs of code
} );

在上面的例子中,你函数代码中的$(this)将指向$('table.accordion-header'),而不是像你预期的那样指向$(document)。
进一步的解释在这里:.on()与$(this)一起使用

0
在jQuery 1.7.2源代码中,“live”基本上指向“on”,因此这个问题可能与“on”函数无关。这需要被排除。on的选择器可能是一个问题。
jQuery源代码:
live: function( types, data, fn ) {
    jQuery( this.context ).on( types, this.selector, data, fn );
    return this;
},

如果您仔细查看此代码并阅读其他答案,您会发现问题在于他们将选择器“'table.accordion-header'”放在了.live()等效的.on()的错误位置。 - jfriend00
我想说的是,“live”和“on”是一样的,“live”指向“on”。这是选择器问题,不是live或on的问题。 - Dennis Rongo
为什么你要将我的答案标记为无用的,当原始问题中,发布者假设将“live”更改为“on”是问题所在。我不得不指出“on==live”,这只是建议排除他对两者的最初误解。 - Dennis Rongo
1
在我看来,你没有回答他们的问题。你提供了一个找寻答案的地方的想法,甚至对于应该查看什么内容也相当模糊。你说:“on 的选择器可能是一个问题。”他们需要改变选择器吗?他们应该如何修复它?这最多只能算是一条评论,因为这不是一个答案。你自己甚至都不确定这是否是正确的方向,基于你写作的语气,并且你没有告诉他们如何解决它。 - jfriend00
那么人们因为试图指向可能的答案而受到惩罚吗?上面那个人回答了这个问题吗?如果是,那么这与我的回答有什么不同呢?这是一个问答网站,每个答案或可能导致答案的建议都是好的,应该考虑。我完全错了吗?我认为不是。仅仅因为你的答案是正确的,并不意味着其他所有答案都是错误的。 - Dennis Rongo
1
抱歉,Dennis。我认为我们不需要将这变成更多的观点分歧。即使一些非常有帮助的评论不是实际问题的答案,也应该作为评论而不是答案发布。这是SO想要的,也是他们认为问答格式最好的方式。如果您对如何将选择器放在不同位置上更加具体(就像Gaby的答案一样),我会认为它是一个有效的答案。 - jfriend00

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接