jQuery - 在单个事件处理程序中组合选择器的问题

时间:2010-11-30 15:22:55

标签: jquery

这是关于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);
   }
});

Patrick的评论

麻烦在于它有效地将.delegate()遭受的低效率(针对选择器进行测试)与分配多个冗余处理程序的低效率相结合。所以你得到两个世界中最糟糕的。

@John - 是的,将它们分解为单独的处理程序更有意义,并将它们共享的任何常用功能放入可以在处理程序中调用的命名函数中。这消除了在每次事件发生时运行.is()测试的需要,这可能是昂贵的。测试被点击的元素有时是有益的。这就是.delegate()的作用。您将承受测试的费用,但会从分配的处理程序数量减少中获益


有人可以(详细地)解释帕特里克谈论的效率低下吗?为什么.is()在这种情况下代价高昂?您能否使用.delegate()

举例说明

4 个答案:

答案 0 :(得分:4)

使用jQuery的.delegate()方法会受到性能影响,因为每次事件发生在具有委托处理程序的元素内部时,都需要进行类似的测试以确定哪个元素收到了事件。

这通常是值得的,因为通过使用.delegate(),您(可能)无需为每个元素分配单独的处理程序。

使用上面的代码,您需要分配多个处理程序的开销,并且您仍在运行需要测试的代码以查看接收到该事件的代码。

很难说.delegate()是否适合您引用的问题,但分配单个处理程序会更好,并避免if( $(this).is('something') )测试。

如果原始OP代码的目的是为每种元素类型提供单独的功能,但仍然让它们共享某些常用功能的子集,那么最好将该通用功能滚动到它自己的命名函数中并调用它。这是一种更有效的方法。


修改

举个例子。假设span.targetp.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表示(假设您为pspan使用了单独的函数。


使用.delegate(),只为容器分配处理程序。这是针对应该触发事件的每种元素完成的。

如您所见,只分配了两个处理程序。一个用于<p>元素,另一个用于<span>。这显然减少了所需的处理程序数量。但是费用是jQuery需要为.delegate()内发生的每个事件运行您传递给container的选择器,以查看哪个类型的元素实际收到了该事件。 / p>

所以有一些给予和接受。

$('#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>

上一个答案中代码的问题在于它有效地将第一个示例(分配了许多处理程序)的低效率与第二个示例(运行选择器)的低效率结合起来。这就是我所说的两个世界中最糟糕的情况。

答案 1 :(得分:2)

为什么效率会降低?在这种情况下,主要是因为您将this转换为jQuery对象,每次点击每个元素额外3次,其中:

$("#container").delegate('a.button', 'click', function() {
  alert("a.button was clicked");
}).delegate('span.xyz', 'click', function() {
  alert("span.xyz was clicked");
}).delegate('a.another', 'click', function() {
  alert("a.another was clicked");
});

将一次绑定到容器(3个处理程序)并在每次单击时运行3个选择器中的每一个,而不是在所有绑定元素上具有n个处理程序(元素数)。因此,绑定时间较短,并且整个处理程序的数量(假设有3个以上的元素)在大页面中较低,因为它总是精确地附加3。

此外,您不需要支付初始$('a.button, span.xyz, a.another')选择器的费用,以便在开始时找到所需的元素。

答案 2 :(得分:0)

使用多重选择器指示该函数足够通用以用于所有选定元素的方式效率低下。

在我看来,最好是单独选择每个选择器并将click事件附加到它。那对我来说也会更自然。

答案 3 :(得分:0)

根据我上面的评论......(这可能更简单等等)

<!-- using unique IDs or attributes to solve the issue -->
<p><span id="elementA">elementA</span></p>
<div id="elementB">elementB</div>
<script type="text/javascript">
$(document).ready(function(){
     $('div, p span').click(function(){
        var id = $(this).attr('id');
        alert('You clicked ' + $('#' + id).text());
     });
});
</script>

或者让标签类型为您处理,如果这适合您的情况

<p><span>elementA</span></p>
<div>elementB</div>


<script type="text/javascript">
 $(document).ready(function() {
    $('div, p span').click(function() {
        var tagName = $(this)[0].tagName;
        alert(tagName); 
    });
});
</script>