这是关于 Patrick DW 对我对此问题的回答的评论。
Multiple selectors: identify the triggering one?
我的答案:
使用 $(this) 将获取被单击的元素..并使用 is()可以帮助您确定点击的内容。
$('a.button, span.xyz, a.another').click(function(e) {
if ($(this).is("a.button")) {
alert("a.button was clicked");
} else if ($(this).is("span.xyz")) {
alert("span.xyz was clicked");
} else if($(this).is("a.another")) {
alert("a.another was clicked);
}
});
帕特里克的评论
这样做的问题在于,它有效地将 .delegate() 所遭受的低效率(针对选择器进行测试)与分配多个冗余处理程序的低效率结合起来。所以你会得到两全其美的结果。
@John - 是的,将它们分解为单独的处理程序,并将它们共享的任何公共(public)功能放入可以从处理程序内部调用的命名函数中会更有意义。这消除了在每次事件发生时运行 .is() 测试的需要,这可能是昂贵的。有时测试被单击的元素可能会很有帮助。这就是 .delegate() 的作用。您承担了测试费用,但从分配的处理程序数量减少中获益
有人可以(详细地)解释帕特里克所说的低效率吗?为什么在这种情况下 .is()
成本高昂?您能否也给出一个使用 .delegate()
最佳答案
使用 jQuery 的 .delegate()
方法会受到性能影响,因为每次事件在具有委托(delegate)处理程序的元素内发生时,都需要进行类似的测试来确定哪个元素接收到该事件。
这通常是值得的,因为通过使用 .delegate()
您(大概)避免了为每个元素分配单独的处理程序的需要。
使用上面的代码,您需要分配多个处理程序,并且您仍在运行需要测试以查看哪个处理程序接收到事件的代码。
很难说是否.delegate()
是您引用的问题的适当选择,但最好分配单独的处理程序,并避免 if( $(this).is('something') )
测试。
如果原始OP代码的目的是为每个元素类型提供单独的功能,但仍然让它们共享公共(public)功能的一些子集,那么最好将该公共(public)功能滚动到其自己的命名函数中并调用它。这是一种更有效的方法。
编辑:
举这个例子。假设span.target
和p.anothertaget
元素是为了获取处理程序。正如您所看到的,容器中有许多元素。
使用选择器分配 .click()
,您最终会得到几个单独的事件处理程序。
$('span.target').click(function() { /* do something with span */ });
$('p.anothertarget').click(function() { /* do something with p */ });
html
<div id='container'>
<span class='target'>click me</span> <!-- i get a handler -->
<div>i don't do anything</div>
<p class='anothertarget'>i get a click too</p> <!-- i get a handler -->
<span class='target'>click me</span> <!-- i get a handler -->
<div>i don't do anything</div>
<p class='anothertarget'>i get a click too</p> <!-- i get a handler -->
<span class='target'>click me</span> <!-- i get a handler -->
<div>i don't do anything</div>
<p class='anothertarget'>i get a click too</p> <!-- i get a handler -->
<span class='target'>click me</span> <!-- i get a handler -->
</div>
这意味着 jQuery 需要管理所有这些元素的单独处理程序。这是缺点。好处是您不需要运行选择器来查看接收到事件的内容。它将始终由 this
表示(假设您对 p
和 span
使用了单独的函数。
使用.delegate()
,您仅将处理程序分配给容器。这是针对应触发事件的每种类型的元素完成的。
如您所见,仅分配了两个处理程序。一个为<p>
元素,另一个为 <span>
。这显然减少了所需处理程序的数量。但代价是 jQuery 需要运行您传递给 .delegate()
的选择器。对于 container
内发生的每个事件查看哪种类型的元素实际接收到了事件。
所以有一些让步。
$('#container').delegate('span.target','click',function() { /* do something with span */ });
.delegate('p.anothertarget','click',function() { /* do something with p */ });
html
<div id='container'> <!-- i get a handler for the span.target -->
<!-- and for p.anothertarget -->
<span class='target'>click me</span>
<div>i don't do anything</div>
<p class='anothertarget'>i get a click too</p>
<span class='target'>click me</span>
<div>i don't do anything</div>
<p class='anothertarget'>i get a click too</p>
<span class='target'>click me</span>
<div>i don't do anything</div>
<p class='anothertarget'>i get a click too</p>
<span class='target'>click me</span>
</div>
您之前的答案中的代码的问题在于,它有效地将第一个示例的低效率(分配了许多处理程序)与第二个示例的低效率(运行选择器)结合在一起。这就是我所说的两全其美的意思。
关于jQuery - 在单个事件处理程序中组合选择器的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4315308/