2010-11-30 11 views
2

これは、この質問に対する私の答えに対するPatrick DWのコメントに関するものです。jQuery - 単一のイベントハンドラでセレクタを組み合わせる際の問題

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 - そうですね、それらを別々のハンドラに分割し、それらが共有する共通の機能をハンドラ内から呼び出せる名前付き関数に配置する方が意味があります。これにより、すべてのイベント発生時に.is()テストを実行する必要がなくなり、コストがかかる可能性があります。クリックされた要素をテストすると有益な場合があります。これが.delegate()の動作です。あなたは、テストの費用を被るが、


を割り当てられているハンドラ数の減少から増加には、誰かが(詳しく)パトリックが話している非効率性を説明してもらえますか?このシナリオでは.is()はなぜ高価なのですか? .delegate()

+0

のために適切なだ場合、あなたの質問は何ですか?あなたのためのタグタイプのハンドルの事を聞かせて編集:[OK]を、ちょうどそれを見た。 – pyvi

+0

このシナリオでは、一意のIDを実装するのに費用がかからず、簡単にはできませんか? IE element1 is id = "clickA" element2 is id = "clickB"次に、属性IDを1回取得するだけで、セレクタに対するテストの問題は解決され、1つの関数を保持できます。 (もしあなたがこの仕様を打ち負かすことなく大丈夫なら、あなた自身の擬似属性、つまりmyattrib = "selectorA"を簡単に使うことができますが、実際には良くありませんが、まさにこの理由のために全面的に使用されています) –

答えて

4

jQueryの.delegate()メソッドを使用すると、イベントがデリゲートハンドラで要素内で発生するたびに、どの要素がイベントを受け取ったかを判断するために同様のテストが行​​われる必要があるため、パフォーマンスが低下します。

.delegate()を使用すると、個々のハンドラをすべての要素に割り当てる必要性が(おそらく)避けられるため、これはしばしば価値があります。

上記のコードでは、複数のハンドラを割り当てるオーバーヘッドがありますが、どのイベントを受信したかを確認するためにはテストする必要があります。

.delegate()があなたが参照した質問には適切な選択肢だとは言いにくいが、個々のハンドラを割り当てて、if($(this).is('something'))のテストを避ける方がはるかに良いだろう。

元のOPのコードの目的が要素型ごとに個別の機能を持ちながらも共通の機能の一部を共有していたのであれば、その共通の機能を独自の名前付き関数にロールして呼び出す方が良いでしょう。これははるかに効率的なアプローチです。


EDIT:

この例を見てみましょう。 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のは、これらの要素のすべてのための個別の利きを管理する必要があることを意味します。これは欠点です。イベントを受け取ったものを見るためにセレクタを実行する必要はありません。それは常にあなたがpspanために別々の機能を使用すると仮定すると(thisで表されます。


.delegate()を使用して、あなただけのコンテナにハンドラを割り当てる。これは、トリガすべき要素の種類ごとに行われます

<p>要素の場合は1つ、<span>の場合はもう1つのハンドラが割り当てられています。これは明らかに必要なハンドラの量を減らしますが、費用は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> 

以前の回答のコードで問題は、それが効果的に第二の非効率と(多くのハンドラが割り当てられている)第一の例の非効率性を組み合わせたことでした例(セレクターの実行)。それは私が両方の世界の中で最悪のことを意味していたものです。

+0

@patrick dw。私はあなたがis( 'something')の使用を避けることを理解していますが、is( "something")を使用することについては非常に非効率です。大きな違いはパフォーマンスですか? –

+1

@John - 新しいブラウザのいくつかは 'matchesSelector()'と呼ばれるものを持っています。これはjQueryが( '.is()'のようなメソッドがはるかに高速に動作することを意味します。使用されているほとんどのブラウザーにはこれがないので、Sizzleセレクターエンジンを実行する必要があります。これはずっと遅くなります。それはあなたのアプリケーションを殺すでしょうか?しかし、それは良いアプローチではありません。特に、実際にはそれに利益はありません。 – user113716

+0

@Patrick DW ...説明をありがとう。 –

0

複数のセレクタを使用すると、関数が選択されたすべての要素に使用できるほど一般的であることを示す方法は非効率的です。

私の視点では、個々のセレクタを個別に選択してクリックイベントをアタッチする方がよいでしょう。それはまた私にとってより自然に見えます。

2

なぜ効率が悪いですか?この場合、あなたはjQueryのにthisをキャストしている主な理由として要素、あたりのクリックあたりの余分な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つのハンドラ)に一度結合するとのそれぞれを実行しますすべてのバインドされた要素のハンドラ(要素数)をnにするのではなく、1回のクリックで3つのセレクタを使用できます。したがって、バインディング時間が短くなり、全体のハンドラ(3以上の要素があると仮定します)の数は、大きなページではより遠く、常に正確に3になるので、常に正確に3になります。

また、最初の$('a.button, span.xyz, a.another')セレクタを使用して、開始時に必要な要素を見つけます。

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> 

ORそれはあなたのケース

<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> 
関連する問題