jQuery click,bind,live,delegate,trigger和on功能之间的区别(示例)?


139

我已经阅读了有关每个功能的文档 jQuery official website,但是以下函数之间没有此类比较列表:

$().click(fn)
$().bind('click',fn)
$().live('click',fn)
$().delegate(selector, 'click', fn)
$().trigger('click') // UPDATED
$().on('click', selector ,fn); // more UPDATED

请避免任何参考链接。

以上所有功能如何正确发挥作用?在哪种情况下应首选哪个功能?

注意:如果还有其他具有相同功能或机制的功能,请详细说明。

更新资料

我也看过 $.trigger功能。它是否与上述功能类似?

更多更新

现在.onv1.7中添加了,我认为这一方式某种程度上涵盖了所有上述功能要求。


3
@I和PHP一样,有时人们如果不认为这不是手册无法回答的问题,或者似乎是一项家庭作业问题,便会否决。不用担心,如果其他人觉得有用,就会投票赞成。
typeoneerror 2010年

@Typeoneerror-感谢支持,我已经阅读了手册,当我不明白明显的区别时,请在此处发布。
diEcho 2010年

3
@I Like PHP-编辑了一些清理问题...这经常被问到,但很少这样,它很容易成为有价值的谷歌资源。我同意的是这样一个维基十岁上下的条目将是非常有益的,我看到混乱绕过这个问题,尤其是.live().delegate()几乎每天都+1一个完全有效的问题。
尼克·克雷弗

@Nick Craver感谢您的编辑,实际上我的英语不好(笑)。有任何关于如何在上发布问题的意见/参考SO。它只是
凭经验

@I喜欢PHP-两者兼而有之,所以这里有一个很棒的SO 通用问答:meta.stackexchange.com/questions/7931对于短语/评论,您只是开始学习什么是合适的并且是最好的方法传达您的想法,代码>任何描述,有时,使用正确的关键字,进行适当的标记,我想您到这里的时间就会越来越长,随着时间的推移,我看到许多海报在不断完善。至于您的编辑,.trigger()只需调用事件处理程序...我将在下面的答案中添加描述。
尼克·克雷弗

Answers:


162

在阅读本文之前,请将该事件列表拉到另一页,API本身是非常有用的,并且我在下面讨论的所有内容都直接从此页面链接

首先,.click(function)实际上是的快捷方式.bind('click', function),它们是等效的。将处理程序直接绑定到元素时,可以使用它们,例如:

$(document).click(function() {
  alert("You clicked somewhere in the page, it bubbled to document");
});

如果此元素被替换或丢弃,则该处理程序将不再存在。同样,运行此代码以附加处理程序不存在的元素(例如,选择器随后找到了)将无法获取处理程序。

.live()并且.delegate()具有相似的相关性,.delegate()实际上是在.live()内部使用的,它们都侦听事件冒泡。 这适用于新元素和旧元素,它们以相同的方式起泡事件。您可以在元素可能更改时使用这些元素,例如添加新行,列表项等。如果没有留在页面中且在任何时候都不会被替换的父/共同祖先,请使用.live(),例如:

$(".clickAlert").live('click', function() {
  alert("A click happened");
});

但是,如果在某个地方确实有一个父元素没有被替换(因此其事件处理程序不会再见),则应使用来处理它.delegate(),如下所示:

$("#commonParent").delegate('.clickAlert', 'click', function() {
  alert("A click happened, it was captured at #commonParent and this alert ran");
});

这项工作与几乎相同.live(),但是事件在捕获和执行处理程序之前冒泡的次数更少。这两种方法的另一个常见用法是说您的类在某个元素上进行了更改,不再与您最初使用的选择器匹配...使用这些方法,选择器将在事件发生时进行评估,如果匹配,则处理程序运行。 .so不再与选择器匹配的元素很重要,它将不再执行。随着.click()然而,事件处理程序的DOM元素上绑定的权利,但事实上,它不匹配任何选择来发现这是无关紧要的......该事件被约束,它一直待到该元素消失了,或者处理器通过删除.unbind()

然而,对于另一种常见的使用.live().delegate()性能。如果要处理大量元素,则将点击处理程序直接附加到每个元素上既昂贵又耗时。在这些情况下,设置单个处理程序并让冒泡进行工作更为经济,请看一下这个问题所起的巨大作用,这是应用程序的一个很好的例子。


触发方式 -针对更新的问题

有2个主要的事件处理程序触发函数可用,它们属于API中相同的“事件处理程序附件”类别,分别是.trigger().triggerHandler().trigger('eventName')具有一些常见事件内置的快捷方式,例如:

$().click(fn); //binds an event handler to the click event
$().click();   //fires all click event handlers for this element, in order bound

您可以在此处查看包含这些快捷方式的列表

至于差异,则.trigger()触发事件处理程序(但大多数时候不是默认操作,例如,将光标放在clicked中的正确位置<textarea>)。它使事件处理程序按照绑定的顺序发生(如本机事件将发生),触发本机事件操作,并使DOM冒泡。

.triggerHandler()通常是出于不同的目的,在这里您只是尝试触发绑定的处理程序,它不会导致触发本机事件,例如提交表单。它不会使DOM冒泡,并且不能链接(它返回该事件的最后绑定事件处理程序返回的任何内容)。例如,如果您想触发一个focus事件但实际上并不关注对象,则只想.focus(fn)运行绑定的代码,就可以这样做,而.trigger()实际上却可以使元素聚焦并冒泡。

这是一个真实的例子:

$("form").submit(); //actually calling `.trigger('submit');`

这将运行任何提交处理程序,例如jQuery验证插件,然后尝试提交<form>。但是,如果您只是想验证,因为它是通过submit事件处理程序挂接的,但<form>之后没有提交,则可以使用.triggerHandler('submit'),例如:

$("form").triggerHandler('submit');

如果验证检查未通过,该插件会通过轰炸来阻止处理程序提交表单,但是通过这种方法,我们不在乎它做什么。无论是中止与否我们不试图提交表单,我们只是想把它触发重新验证和别的什么也不做。(免责声明:这是一个多余的示例,因为.validate()插件中有一个方法,但这是一个不错的意图说明)


很彻底 一个小的更正:trigger不触发本地事件。原生是指用fireEvent(IE)或dispatchEvent(w3c)模拟的事件。
新月新鲜

@Crescent-更新为不那么模棱两可,我的意思是它触发了本机事件操作,例如表单提交,链接跟随等...希望更新更加清晰:)
Nick Craver

从我正在阅读的内容中@Nick看来,您的主张与您在live()此处给我的主张有所不同:stackoverflow.com/questions/3981762/…使用时是否仍然要考虑“重量” live()
Yahel 2011年

@yahelc-是的,当然……这个答案是严格比较事件处理程序的选项及其特定目的的。权重成本,初始绑定数,是否要动态添加任何内容以及初始选择器仍然是有效的问题。如果您的页面结构不是那么大,那么您就没有那么多事件,那么您就可以了...对重量的关注与结构的大小/深度以及事件数(您的.live()呼叫监听的类型,例如click),因为它会为每个选择器运行选择器。
尼克·克拉弗

1
在jQuery 1.7中,不建议使用live(),而推荐使用$(document).on()。
同步

28

前两个是等效的。

// The following two statements do the same thing:
$("blah").click( function() { alert( "Click!" ); } );
$("blah").bind( "click", function() { alert( "Click!" ); } ); 

但是,通过指定多个以空格分隔的事件名称,第二个事件可用于同时绑定到多个事件:

$("blah").bind( "click mouseover mouseout", function() { alert( "Click! Or maybe mouse moved." ); } ); 

.live方法更有趣。考虑以下示例:

<a class="myLink">A link!</a>
<a id="another">Another link!</a>

<script>
    $("a.myLink").click( function() { alert( 'Click!' ); } );

    $("a#another").addClass( "myLink" );
</script>

在脚本的第二行执行之后,第二个链接还将具有CSS类“ myLink”。但是它将没有事件处理程序,因为在附加事件时它没有该类。

现在考虑您希望它是相反的方式:每当类“ myLink”的链接出现在页面上的某个位置时,您希望它自动具有相同的事件处理程序。当您拥有某种类型的列表或表时,这是很常见的,您可以在其中动态添加行或单元格,但希望它们都以相同的方式运行。您可以使用以下.live方法来代替每次都重新分配事件处理程序的所有麻烦:

<a class="myLink">A link!</a>
<a id="another">Another link!</a>

<script>
    $("a.myLink").live( "click", function() { alert( 'Click!' ); } );

    $("a#another").addClass( "myLink" );
</script>

在此示例中,第二个链接一旦获得“ myLink”类,也将获得事件处理程序。魔法!:-)

当然,这不是字面意思。什么.live确实是处理程序不附加到指定元素本身,而是对HTML树(“身体”元素)的根源。DHTML中的事件具有“冒泡”这一有趣的功能。考虑一下:

<div> <a> <b>text</b> </a> </div>

如果单击“文本”,则首先<b>元素将获得“单击”事件。之后,<a>元素将获得一个“ click”事件。之后,<div>元素将获得一个“ click”事件。依此类推-一直到<body>元素。这就是jQuery将捕获事件并查看是否有任何“实时”处理程序适用于首先导致事件的元素的地方。整齐!

最后是.delegate方法。它只接受符合给定选择器的元素的所有子代,并将“实时”处理程序附加到它们。看一看:

$("table").delegate( "td", "click", function() { alert( "Click!" ); } );

// Is equivalent to:
$("table").each( function() {
    $(this).find( "td" ).live( "click", function() { alert( "Click!" ); } );
} );

有什么问题吗


为了准确起见.live(),请document不要绑定<body>:)您可以在此处查看演示,只需拉起控制台进行检查:jsfiddle.net/aJy2B
Nick Craver

3
这样解释起来更方便。:-)
Fyodor Soikin

4
在“ body”部分足够公平,但是“一直到<body>元素”一直是错误的,事件继续冒泡,那里不是.live()处理程序所在的地方,而是在上面的位置document:)您可以看到一个这里的演示:jsfiddle.net/S2VBX
Nick Craver

8

从jQuery 1.7开始,不推荐使用.live()方法。如果您使用的是jQuery版本<1.7以下,则官方建议在.live()上使用.delegate()。

.live()现在已替换为.on()。

最好直接访问jQuery网站以获取更多信息,但是这是.on()方法的当前版本:

.on( events [, selector] [, data], handler(eventObject) )
.on( events-map [, selector] [, data] )

http://api.jquery.com/on/


2

$().click(fn)并且$().bind('click', fn)是一见钟情相同,但$.bind版本是有两个原因更强大:

  1. $().bind()允许您将一个处理程序分配给多个事件,例如$().bind('click keyup', fn)
  2. $().bind()支持命名空间事件-如果您只想删除(解除绑定)元素绑定的某些事件处理程序,则此功能非常强大-在“ 命名空间事件”中阅读更多内容。

直播与委托:其他答复中已经回答了这一问题。


1

这是阅读API可能会有所帮助的地方。但是,我知道我的头顶,所以您可以继续保持懒惰(是的!)。

$('#something').click(fn);
$('#something').bind('click',fn);

这里(我知道)没有区别。 .click只是一种方便/帮手的方法.bind('click'

// even after this is called, all <a>s in
// <div class="dynamic_els"> will continue
// to be assigned these event handlers

$('div.dynamic_els a').live(‘click’,fn);

这是非常不同的,因为.live向您传入的选择器添加了事件(您尚未在此处选择),并在插入/删除节点时继续查看DOM。

$('#some_element').delegate('td','click',fn);

这只是有所不同,因为您分配事件处理程序的方式不同。 .delegate以DOM事件冒泡为中心。基本原理是,每个事件都会在DOM树中向上冒泡,直到到达根元素为止(document或者,window或者,<html>或者<body>,我不记得了)。

无论哪种方式,您都将一个onclick处理程序绑定到其中的所有<td>s $('#some_element')(您必须指定选择器,尽管您可以说$(document))。单击其子级之一时,事件会冒泡到<td>。然后,您可以提取事件的源元素(jQuery为您自动完成)。

当存在大量元素并且您仅会经历这些事件的几个(或一个中心)点时,这很有用。这样可以节省浏览器的工作量和内存,以将这些事件处理程序合并为更少的对象。


1
.live() 可以避免事件冒泡,实际上.delegate()是的包装器.live(),它只是添加上下文并绑定到元素上,不是document捕获气泡。我认为您对冒泡处理程序的工作方式的理解有点差(我认为这是jQuery 1.4最常被误解的方面)。该处理程序在您绑定到该元素的元素上,因此无论您调用什么元素.delegate(),或者document在情况下.live(),当事件冒泡到那里时,它都会检查目标以查看其是否与选择器匹配,然后执行。
尼克·克雷弗
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.