直接と委任-jQuery .on()


159

私は、jQuery .on()メソッドを使用して、直接イベントハンドラと委任イベントハンドラのこの特定の違いを理解しようとしています。具体的には、この段落の最後の文:

ときにselector提供され、イベントハンドラが呼ばれる委任します。ハンドラーは、イベントがバインドされた要素で直接発生した場合には呼び出されず、セレクターに一致する子孫(内部要素)に対してのみ呼び出されます。jQueryは、イベントターゲットからハンドラーが接続されている要素(つまり、最も内側から最も外側の要素)までイベントをバブルし、そのパスに沿ってセレクターに一致するすべての要素のハンドラーを実行します。

「要素のハンドラを実行する」とはどういう意味ですか?コンセプトを試すためのテストページを作成しました。ただし、次の両方の構成は同じ動作になります。

$("div#target span.green").on("click", function() {
   alert($(this).attr("class") + " is clicked");
});

または、

$("div#target").on("click", "span.green", function() {
   alert($(this).attr("class") + " is clicked");
});

多分誰かがこの点を明確にするために別の例を参照できますか?ありがとう。


7
関心のあるすべてのユーザー
dgo

1
@KevinWheeler以下のフィドルについてコメントしましたが、ここでは基本的に正しく設定されていません(親要素にバインドしており、委任は子を対象としています)。あなたの質問moeyに答えるということは、委任されたハンドラーが新しく追加された要素と一致することを意味しますが、委任されていないものは一致しません。委任には、ブラウザーにフックされるイベントが少なくなり、アプリのメモリ消費が少なくなるという利点がありますが、クリックを処理する時間を(少なくとも)長くするというトレードオフがあります。ゲームを作成している場合は委任しないでください。
vipero07

1
参照している「テストページ」が機能していません。
Jaime Montoya

回答:


373

ケース1(直接):

$("div#target span.green").on("click", function() {...});

==おい!div#target内のすべてのspan.greenがリッスンするようにします。クリックされたら、Xを実行します。

ケース2(委任):

$("div#target").on("click", "span.green", function() {...});

==こんにちは、div#target!「span.green」である子要素のいずれかがクリックされたら、それらを使用してXを実行します。

言い換えると...

ケース1では、これらのスパンのそれぞれに個別に指示が与えられています。新しいスパンが作成された場合、それらは指示を聞いておらず、クリックに応答しません。各スパンは、それ自体のイベントを直接担当します。

ケース2では、コンテナのみに指示が与えられています。子要素に代わってクリック気付く責任があります。イベントをキャッチする作業が委任されました。これは、将来作成される子要素に対しても指示が行われることを意味します。


45
それは素晴らしい説明であり、私が長い間理解することを拒否してきた問題を明確にしました。ありがとう!
dgo

3
それで、それがon()使用とほとんど同じであるのに、なぜ2つの引数を許可するのclick()ですか?
ニッポン

5
.on()は、複数の異なるイベントを含むあらゆる種類のイベントを処理できる汎用APIです(最初の文字列に複数のイベント名を入れることができます)。.click()は、最初のフォームの省略形にすぎません。
N3dst4 2013

1
@ newbie、@ N3dst4:e.targetクリックイベントの最初のターゲットになります(子がある場合span.greenは子ノードにもなります)。ハンドラー内から、this参照を使用する必要があります。このフィドルを参照してください。
LeGEC 2014

1
委任のトピックに追加するもう1つの注意点-非常に便利で効率的です。委任では、一致するすべての要素にイベントをアタッチするよりも、使用するブラウザーリソースを少なくします。人々が委任を使用するより多くの理由が必要になった場合に備えて、私はそれを言及すると思いました。
phatskat 14年

6

1つ目の方法は$("div#target span.green").on()、コードの実行時にセレクターに一致するスパンにクリックハンドラーを直接バインドする方法です。これは、他のスパンが後で追加された(またはそれらのクラスが一致するように変更された)場合、それらを逃し、クリックハンドラーがないことを意味します。また、スパンの1つから後で「グリーン」クラスを削除しても、そのクリックハンドラーは引き続き実行されます。jQueryは、ハンドラーの割り当て方法を追跡せず、セレクターがまだ一致するかどうかを確認します。

2番目の方法$("div#target").on()は、クリックハンドラーを一致するdivにバインドします(これも、その時点で一致するものに対してです)が、div内のどこかでクリックが発生すると、ハンドラー関数はクリックがdiv内だけでなく、2番目のパラメーターのセレクター.on()「span.green」に一致する子要素で発生しました。このようにして、子スパンがいつ作成されたかは関係ありません。子スパンをクリックしても、ハンドラーは実行されます。

したがって、コンテンツを動的に追加または変更していないページの場合、2つの方法の違いに気付くことはありません。追加の子要素を動的に追加する場合、2番目の構文は、親で一度行ったので、クリックハンドラーをそれらに割り当てることを心配する必要がないことを意味します。


5

N3dst4の説明は完璧です。これに基づいて、すべての子要素がbodyの内部にあると想定できるため、これのみを使用する必要があります。

$('body').on('click', '.element', function(){
    alert('It works!')
});

直接またはデリゲートイベントで動作します。


2
jqueryは、スクリプトがbody内のすべての子を検索する必要があるため、遅いため、bodyを使用しないことをお勧めします。要素の中間の親コンテナを使用する方が(高速)なのです。
mikesoft 2015

1
jqueryはあなたが示したのと同じことをしていたライブメソッドを削除しました。これはパフォーマンスが低いため、使用しないでください。
Maciej Sikora 2016

最近のブラウザでは、$('body').on()からの委譲はコールバック内の.elementネイティブdocument.body.addEventHandler()とまったく同じように動作するはずif (Event.target.className.matches(/\belement\b/))です。$.proxyオーバーヘッドが原因でjqueryの方が少し遅くなるかもしれませんが、それについては引用しないでください。
カウベルト

2

OPに接しますが、この機能の混乱を解くのに役立つ概念は、バインドされた要素は選択された要素の親である必要があるということです。

  • バウンドとは、の残りの部分を指し.onます。
  • Selectedはの2番目の引数を参照し.on()ます。

委任は.find()のように機能せず、バインドされた要素のサブセットを選択します。セレクターは、厳密な子要素にのみ適用されます。

$("span.green").on("click", ...

とは大きく異なります

$("span").on("click", ".green", ...

特に、@ N3dst4が「将来作成される要素」のヒントを得るには、バインドされた要素が永続的な親である必要があります。その後、選択した子供たちが行き来できます。

編集

委任.onが機能しない理由のチェックリスト

$('.bound').on('event', '.selected', some_function)うまくいかないかもしれないトリッキーな理由:

  1. バインドされた要素は永続的ではありません。呼び出し後に作成されました.on()
  2. 選択された要素は、バインドされた要素の適切なではありません。同じ要素です。
  3. 選択された要素は、を呼び出すことによって、バインドされた要素へのイベントのバブリングを防ぎました.stopPropagation()

(セレクターのスペルミスなど、それほど複雑ではない理由を省略しています。)


1

直接のイベントと委任されたイベントを比較した投稿を書きました。私は純粋なjsを比較しますが、それだけをカプセル化するjqueryと同じ意味があります。

結論は、委任されたイベント処理は、ユーザーがページを操作している間にバインドされた要素を作成できる動的なDOM構造用であり(バインディングを再度行う必要はありません)、構造が変更されないことがわかっている場合、直接的なイベント処理は静的なDOM要素用です。

詳細および完全な比較について -http://maciejsikora.com/standard-events-vs-event-delegation/

常に委任されたハンドラーを使用することは、現在非常にトレンディだと思いますが、それは正しい方法ではありません。多くのプログラマーは、「使用する必要がある」ので、それを使用します。違いの知識によって。


多くのイベントハンドラー(たとえば、テーブルの各行)をアタッチする場合、多くの直接ハンドラーをアタッチするよりも、コンテナーに単一の委任ハンドラーを使用する方がパフォーマンスが優れていることがよくあります。これは、イベントハンドラーカウント自体がプロファイリングメトリックであるという基本的な事実からわかります。
カウバート
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.