jQuery .live() 与 .on() 方法,用于在加载动态 html 后添加点击事件

jQuery .live() vs .on() method for adding a click event after loading dynamic html

提问人:Sean Thoman 提问时间:1/6/2012 最后编辑:Sean Thoman 更新时间:10/2/2019 访问量:156691

问:

我正在使用 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 是一个动态加载的元素。

谢谢。

JavaScript jQuery 事件 DOM 处理程序

评论

25赞 1/6/2012
为什么说“据说已弃用”?你不相信这些文档吗?
6赞 nnnnnn 1/6/2012
不应该被弃用:它已被弃用。如果你看一下 .live() 的 jQuery doco,它会告诉你如何重写现有的 to use or 用法(取决于你是否在 1.7+ 版本上)。请注意,如果您添加一个带有“after”的处理程序,即在动态加载元素之后,它应该可以工作 - 唯一的问题是在动态加载元素之前尝试分配。.live().delegate().on().click().click()
0赞 Sean Thoman 1/6/2012
我把措辞改成了“显然”,因为这基本上就是我的意思。无论如何,我现在明白了,显然,由于 .load() 事件是异步的,因此只能在成功处理程序中可靠地识别 #child 元素,这是有道理的。
0赞 showdev 8/11/2016
动态创建的元素上的事件绑定可能重复吗?

答:

23赞 Larry Williamson 1/6/2012 #1

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

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

当您对任何元素进行匹配时,该事件会冒泡到主文档(只要没有其他侦听器调用方法),这将在事件冒泡到父元素之上。click.selectorevent.stopPropagation()

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

出于几个原因,这是明智的,包括性能和内存利用率(在大规模应用程序中)

编辑:

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

评论

23赞 cHao 1/6/2012
他试过了.这是。不同的野兽。$(element).on(...)$(document).on(...,element,...)
0赞 Larry Williamson 5/10/2018
@ArnoldRoa是的,性能更好。你不会在多个子项上有一个侦听器,不必在修改 DOM 时重新应用侦听器,并且默认情况下事件会通过 DOM 冒泡。运行一次,每个与选择器匹配的子项将在单击时触发给定的函数。
0赞 Gust van de Wal 10/2/2019
@L422Y在这里的评论非常具有误导性。如果您对性能影响感到好奇,请查看 @jfriend00 对 @Jared 答案的评论
0赞 Larry Williamson 10/2/2019
@GustvandeWal 它是如何误导的?如果你去发出一百个$(this).on(...),而不是在父元素上侦听一次事件,它的性能要高得多。
0赞 Gust van de Wal 10/2/2019
你只是在谈论附加事件。实际的性能瓶颈是太多的侦听器(如您委托的侦听器),而不是需要附加事件的大量元素。
6赞 Matt Cashatt 1/6/2012 #2

.on() 适用于 jQuery 1.7 及更高版本。如果您使用的是旧版本,请使用以下命令:

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

评论

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

试试这个:

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

来自 $.on() 文档:

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

当您调用元素时,您的元素不存在,因此该事件不会绑定(与 不同)。但是,确实存在,因此将事件绑定到该事件是可以的。#child$.on()$.live()#parent

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

评论

0赞 Sean Thoman 1/6/2012
如果我在 $.load() 方法之后调用 $.on() 方法,那么为什么 #child 元素在这一点上不存在?
6赞 jfriend00 1/6/2012
@SeanThoman - 必须从方法的成功处理程序调用它,而不是从方法后面的代码调用它。 仅在成功处理程序实际执行时加载,而不是在执行之前。.load().load()#child
0赞 lupos 9/26/2013
即便如此,将您获得的任何数据插入 DOM 所需的时间也意味着它可能无法连接。我最近一直在做很多单页应用程序工作,我的标准是 var $body = $('body');$body.on(“事件”, “.element/#class”, function(e){});为了一切。1 个选择器。无需担心加载或未加载的内容。
618赞 jfriend00 1/6/2012 #4

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

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

事件处理程序将附加到对象上,每当源自 的 click 事件冒泡到它时,它都会触发 click 处理程序。这称为委托事件处理(事件处理委托给父对象)。#parent#child

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

评论

24赞 MikeSchinkel 5/19/2013
很好的解释!我以前从未能够绕开我的脑袋。 但今晚我决定再次尝试,你的解释立即揭示了我一直缺少的东西。谢谢!live()on()
6赞 Brock Hensley 8/15/2013
一百万起。在我意识到这在jQuery中可以用于动态创建的子项之前,我就开始使用knockout,非常感谢。
9赞 Cholesterol 9/24/2013
你应该考虑写一本书什么的:你的小文字对我更有帮助,而不是jQuery文档中关于«on()»的整页。多谢!
0赞 klewis 1/30/2016
@jfriend00您碰巧知道如何将相同的过程应用于悬停、非悬停的情况吗?有没有消息来源谈论这个?
0赞 jfriend00 1/30/2016
@blackhawk - 请参阅此答案。您可以注册 and 事件,并在处理程序中测试触发了哪个事件。jQuery 的伪“悬停”事件不适用于委派。mouseentermouseleave
14赞 Jared 1/6/2012 #5

1.7 中 .live() 的等价物如下所示:

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

基本上,观察文档中的点击事件,并过滤它们以查找 #child。

评论

0赞 cHao 1/6/2012
因为这就是事件处理程序附加到文档的方式(方式如此)。.live()
17赞 jfriend00 1/6/2012
现在弃用的一个原因是,将所有实时事件处理程序放在文档对象上是不好的。事情真的可以放慢速度。不仅事件必须一直冒泡到文档,而且您可能有很多事件处理程序要查看文档对象。其主要优点是可以将其附加到更接近实际对象的父对象,从而大大提高性能。所以。。。我不建议与文档对象一起使用。最好选择一个更接近的父对象。.live().on().on()
0赞 Jared 1/6/2012
感谢您的澄清。值得一提的是,on() 大大提高了事件的性能,因此它应该比以前少了问题。如果附加到父级,我认为它必须是存在于文档就绪的父级,否则您会看到类似的问题。
0赞 Dan Lugg 3/10/2013
在最坏的情况下,这确实会模拟已弃用的方法;但是,控制委派的能力肯定是有利的。.live()
4赞 Coderx07 7/30/2013 #6

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

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

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

将代码编写为:

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

调用 caller();在页面中创建对象后,如下所示。

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

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

10赞 NSV 5/8/2014 #7

我知道现在给出答案有点晚了,但我为 .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() 之前包含它即可。

评论

0赞 Skynet 7/2/2022
将内部调用替换为 ,否则方法链接将不起作用,并且在不可用的环境中也不起作用。return jQuery('body').on(evt, this.selector, func);$