web-dev-qa-db-ja.com

すべてのjqueryイベントを$(document)にバインドする必要がありますか?

これがどこから来たのか

JQueryを初めて学んだとき、通常は次のようなイベントを添付しました。

_$('.my-widget a').click(function() {
    $(this).toggleClass('active');
});
_

セレクターの速度とイベントの委任についてさらに学習した後、「jQueryイベントの委任によりコードが高速化される」ことをいくつかの場所で読みました。そこで、次のようなコードを書き始めました。

_$('.my-widget').on('click','a',function() {
    $(this).toggleClass('active');
});
_

これは、廃止された.live()イベントの動作を複製する推奨方法でもありました。私の多くのサイトは常に動的にウィジェットを追加/削除するので、これは私にとって重要です。ただし、既に存在するコンテナ '.my-widget'に追加された要素のみが動作を取得するため、上記は.live()とまったく同じようには動作しません。そのコードの実行後にhtmlの別のブロックを動的に追加すると、これらの要素はそれらにバインドされたイベントを取得しません。このような:

_setTimeout(function() {
    $('body').append('<div class="my-widget"><a>Click does nothing</a></div>');
}, 1000);
_


私が達成したいこと:

  1. .live()の古い動作//存在しない要素にイベントをアタッチすることを意味する
  2. .on()の利点
  3. イベントをバインドする最速のパフォーマンス
  4. イベントを管理する簡単な方法

次のようにすべてのイベントを添付します。

_$(document).on('click.my-widget-namespace', '.my-widget a', function() {
    $(this).toggleClass('active');
});
_

これは私のすべての目標を達成しているようです。 (はい、IEで遅いですが、理由はわかりませんか?)単一のイベントのみが単一の要素に結び付けられ、セカンダリセレクターはイベントが発生したときにのみ評価されるため、高速です(お願いしますここでこれが間違っている場合は修正してください)名前空間は、イベントリスナーを簡単に切り替えることができるので素晴らしいです。

私のソリューション/質問

だから、jQueryイベントは常に$(document)にバインドされるべきだと考え始めています。
これをしたくない理由はありますか?
これはベストプラクティスと考えられますか?そうでない場合、なぜですか?

このすべてを読んだなら、ありがとう。フィードバック/洞察に感謝します。

仮定:

  1. .on()をサポートするjQueryの使用//少なくともバージョン1.7
  2. 動的に追加されたコンテンツにイベントを追加したい

測定値/例:

  1. http://24ways.org/2011/your-jquery-now-with-less-suck
  2. http://brandonaaron.net/blog/2010/03/4/event-delegation-with-jquery
  3. http://www.jasonbuckboyer.com/playground/speed/speed.html
  4. http://api.jquery.com/on/
155
Buck

いいえ-すべての委任されたイベントハンドラーをdocumentオブジェクトにバインドしないでください。これはおそらく、作成できる最悪のパフォーマンスシナリオです。

まず、イベントの委任が常にコードを高速化するとは限りません。ある場合には、それは有利であり、ある場合にはそうではありません。実際にイベントの委任が必要な場合、およびそれから利益を得る場合は、イベントの委任を使用する必要があります。それ以外の場合は、イベントハンドラーをイベントが発生するオブジェクトに直接バインドする必要があります。これは一般に効率的だからです。

次に、すべての委任されたイベントをドキュメントレベルでバインドしないでください。これは、.live()が非推奨になった理由です。この方法で多くのイベントがバインドされている場合、これは非常に非効率的です。委任されたイベント処理では、動的ではない最も近い親にバインドする方がはるかに効率的です。

第三に、すべてのイベントが機能するわけではなく、すべての問題が委任で解決できるわけでもありません。たとえば、入力コントロールのキーイベントをインターセプトし、無効なキーが入力コントロールに入力されるのをブロックする場合、デリゲートハンドラーにイベントがバブルアップするまでに、デリゲートハンドラーでそれを行うことはできません。入力コントロールによって処理され、その動作に影響を与えるには遅すぎます。

イベントの委任が必要または有利な場合は次のとおりです。

  • イベントをキャプチャしているオブジェクトが動的に作成/削除され、新しいオブジェクトを作成するたびにイベントハンドラを明示的に再バインドする必要なく、それらのイベントをキャプチャしたい場合。
  • まったく同じイベントハンドラを必要とするオブジェクトがたくさんある場合(多くは少なくとも数百)。この場合、セットアップ時に、数百以上の直接イベントハンドラーではなく、委任された1つのイベントハンドラーをバインドする方が効率的です。デリゲートされたイベント処理は、直接イベントハンドラーよりも実行時に常に効率が悪いことに注意してください。
  • ドキュメントの任意の要素で発生するイベントを(ドキュメントの上位レベルで)キャプチャしようとしているとき。
  • デザインでイベントバブリングとstopPropagation()を明示的に使用して、ページの問題や機能を解決している場合。

これをもう少し理解するには、jQueryの委任イベントハンドラーの動作を理解する必要があります。このようなものを呼び出すとき:

_$("#myParent").on('click', 'button.actionButton', myFn);
_

_#myParent_オブジェクトに汎用jQueryイベントハンドラーをインストールします。クリックイベントがこの委任イベントハンドラーにバブルアップすると、jQueryはこのオブジェクトにアタッチされた委任イベントハンドラーのリストを調べ、イベントの元の要素が委任イベントハンドラーのセレクターのいずれかに一致するかどうかを確認する必要があります。

セレクタはかなり複雑になる可能性があるため、jQueryは各セレクタを解析し、元のイベントターゲットの特性と比較して、各セレクタに一致するかどうかを確認する必要があることを意味します。これは安価な操作ではありません。それらのいずれかが1つだけであれば大したことではありませんが、すべてのセレクターをドキュメントオブジェクトに配置し、すべての単一のバブルイベントと比較するセレクターが何百もある場合、これはイベント処理のパフォーマンスを著しく低下させ始める可能性があります。

このため、デリゲートイベントハンドラーをターゲットオブジェクトにできるだけ近づけるように、デリゲートイベントハンドラーをセットアップする必要があります。つまり、デリゲートされた各イベントハンドラーを介してバブルするイベントが少なくなり、パフォーマンスが向上します。すべてのバブルイベントは、すべての委任イベントハンドラーを通過し、すべての可能な委任イベントセレクターに対して評価される必要があるため、すべての委任イベントをドキュメントオブジェクトに配置することは、最悪のパフォーマンスです。これがまさに.live()が廃止された理由です。これは.live()がやったことであり、非常に非効率的であることが判明したためです。


したがって、最適化されたパフォーマンスを実現するには:

  1. 委任されたイベント処理は、必要な機能を実際に提供するか、パフォーマンスを向上させる場合にのみ使用してください。あなたが実際にそれを必要としないとき、それは簡単だからです。実際には、イベントディスパッチ時に、直接イベントバインディングよりもパフォーマンスが低下します。
  2. 可能な限り、イベントのソースに最も近い親に委任されたイベントハンドラーを接続します。イベントをキャプチャする動的要素があるために委任されたイベント処理を使用している場合、それ自体が動的ではない最も近い親を選択します。
  3. 委任されたイベントハンドラーには、評価しやすいセレクターを使用します。委任されたイベント処理の仕組みに従っていると、委任されたイベントハンドラーを多くのオブジェクトと何度も比較する必要があるため、できるだけ効率的なセレクターを選択するか、より単純なセレクターを使用できるように単純なクラスをオブジェクトに追加する必要があることを理解できます委任されたイベント処理のパフォーマンスを向上させます。
207
jfriend00

イベント委任とは、要素が実際にDOMに存在する前にハンドラーを記述する手法です。この方法には欠点があり、そのような要件がある場合にのみ使用してください。

イベントの委任はいつ使用しますか?

  1. 同じ機能を必要とするより多くの要素に共通ハンドラーをバインドする場合。 (例:テーブル行のホバー)
    • この例では、直接バインドを使用してすべての行をバインドする必要がある場合、そのテーブルのn行に対してn個のハンドラーを作成することになります。委任メソッドを使用することにより、これらすべてを1つの単純なハンドラーで処理できます。
  2. DOMで動的コンテンツをより頻繁に追加する場合(例:テーブルの行の追加/削除)

なぜイベントの委任を使用すべきではないのか

  1. イベントを要素に直接バインドする場合と比較すると、イベントの委任は遅くなります。
    • ヒットするすべてのバブルでターゲットセレクターを比較します。比較は複雑であるだけでなく、費用もかかります。
  2. バインドされている要素にヒットするまで、イベントバブリングを制御できません。

PS:動的コンテンツの場合でも、コンテンツがDOMに挿入された後にハンドラーをバインドする場合、イベント委任メソッドを使用する必要はありません。 (動的コンテンツを頻繁に削除/再追加しないで追加する場合)

8

どうやら、現在、イベントの委任が実際に推奨されています。少なくともバニラJSの場合。

https://gomakethings.com/why-event-delegation-is-a-better-way-to-listen-for-events-in-Vanilla-js/

「Webパフォーマンス#ドキュメントのすべてのクリックを聞くのはパフォーマンスに悪いように感じますが、実際には、個々のアイテムに多数のイベントリスナーを配置するよりもパフォーマンスが高くなります。」

0
Reincha