jQuery `click`、`bind`、`live`、`delegate`、`trigger` 和 `on` 函数之间的区别(举个例子)?

IT技术 javascript jquery
2021-01-14 00:37:08

我已经阅读了关于每个函数的文档 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函数。它的工作方式与上述功能类似吗?

更多更新

现在.on是在v1.7中添加的,我认为这个以某种方式涵盖了上述所有功能要求。

5个回答

在您阅读本文之前,将这个事件列表拉到另一个页面中,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()and 的另一个常见用途.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)模拟的事件
2021-03-16 00:37:08
@Crescent - 更新为不那么含糊不清,我的意思是它会触发本机事件操作,例如表单提交、链接跟随等......希望更新更清晰:)
2021-03-16 00:37:08
@Nick 从我正在阅读的内容来看,您的看法似乎与您在live()这里给我的看法不同:stackoverflow.com/questions/3981762/...使用时“重量”仍然是一个问题live()吗?
2021-03-21 00:37:08
在 jQuery 1.7 中,live() 被弃用,取而代之的是 $(document).on()。
2021-03-24 00:37:08
@yahelc - 是的,当然......这个答案严格比较了事件处理程序的选项及其特定目的。权重成本与初始绑定的数量、如果您动态添加任何内容与初始选择器的数量仍然是有效的问题。如果你的页面结构不是那么大,你没有那么多事件,那么你很好......对重量的关注与你的结构的大小/深度和事件的数量(您的.live()呼叫侦听的类型,例如click) 正在生成,因为它为每个运行选择器。
2021-04-07 00:37:08

前两个是等价的。

// 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>

在脚本的第二行执行后,第二个链接也将有一个“myLink”的 CSS 类。但它不会有事件处理程序,因为在附加事件时它没有类。

现在考虑一下您希望它是另一种方式:每次在页面上的某个位置出现带有“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> 元素将获得“点击”事件。之后 <div> 元素将获得一个“点击”事件。依此类推 - 一直到 <body> 元素。这就是 jQuery 将捕获事件并查看是否有任何“实时”处理程序适用于首先导致事件的元素的地方。整洁的!

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

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

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

问题?

在“body”部分足够公平,但是“一直到 <body> 元素”是错误的,事件继续在那里冒泡,而且它不是.live()处理程序所在的地方,它在上面,在document:) 你可以看到一个这里的演示:jsfiddle.net/S2VBX
2021-04-05 00:37:08
准确地说,.live()绑定到documentnot <body>:) 您可以在此处查看演示,只需拉起控制台即可查看:jsfiddle.net/aJy2B
2021-04-07 00:37:08
这样解释比较方便。:-)
2021-04-08 00:37:08

从 jQuery 1.7 开始,不推荐使用 .live() 方法。如果您使用的 jQuery 版本 <1.7,那么官方建议使用 .delegate() 而不是 .live()。

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

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

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

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

$().click(fn)$().bind('click', fn)乍一看完全相同,但由于$.bind两个原因,该版本更强大:

  1. $().bind()允许您将一个处理程序分配给多个事件,例如,$().bind('click keyup', fn)
  2. $().bind()支持命名空间事件 - 如果您只想删除(解除绑定)元素绑定的某些事件处理程序,这是一项强大的功能 - 在Namespaced Events 中了解更多信息

直播 vs 委托:这已经在其他回复中回答了。

这是阅读 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 树,直到它到达根元素(documentorwindow<html>or <body>,我记不清了)。

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

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

.live() 适用于事件冒泡,实际上.delegate()是 的包装器.live(),它只是添加上下文并绑定到元素不是document捕获气泡。我认为您对冒泡处理程序如何工作的理解有点偏离(我认为这是 jQuery 1.4 最常被误解的方面)。处理程序在您绑定到的元素上,因此无论您调用什么元素.delegate(),或者document在 的情况下.live(),当事件冒泡到那里时,它都会检查目标以查看它是否与选择器匹配,如果匹配则执行。
2021-04-12 00:37:08