動的に追加される要素にイベントハンドラーをアタッチしたい
例えばテーブルの各行にクリックイベントをアタッチしたいとき、それがAJAXで非同期にデータをロードするテーブルならばロードのたびにアタッチし直さなければならないし、ユーザーが自由に行追加できるテーブルならばその都度追加行にアタッチしなければならない。
動的にイベントをアタッチするようなコードは、同じイベントを二重にアタッチしてしまう、といった事故を起こしがち。できればイベントのアタッチはページロード時に一発で済ませたい。そんなときはdelegatedなイベントハンドラーを利用するとよい。
環境
jQuery 1.7以降
delegatedなイベントハンドラーとは
イベントの発生元に直接ハンドラーをアタッチするのではなく、親要素にアタッチして子から伝播してきたところを捕まえよう、というコンセプトのハンドラー。
やり方
冒頭に書いたテーブルの例だと以下の通り。
$( "#dataTable tbody" ).on( "click", "tr", function() { console.log( $( this ).text() ); });
説明
tr
ではなくその親要素、tbody
にイベントをアタッチする。イベントの発生元が第2引数のセレクターtr
にマッチしない限りイベントは発火しない。イベントを捕まえるのはtbody
なので、子要素のtr
が増えたり書き換わったりしても影響を受けない。
注意
Attaching many delegated event handlers near the top of the document tree can degrade performance.(中略)For best performance, attach delegated events at a document location as close as possible to the target elements. Avoid excessive use of
document
ordocument.body
for delegated events on large documents.
.on() | jQuery API Documentation
ドキュメントツリーのトップに近い要素にdelegatedなイベントハンドラーを多数アタッチするとパフォーマンスが落ちる可能性がある。document
とかdocument.body
とかにやたらとアタッチするのは避け、できるだけターゲットに近い要素にアタッチしましょう、とのこと。