パンダのメモ帳

技術系のネタをゆるゆると

jQueryで .live() と .bind() を併用する場合の注意

jQuery の .live() メソッドでイベントハンドラを設定した場合、.bind() メソッドで設定したイベントハンドラより後に実行される。以下、検証と詳細。

1. 検証スクリプト

以下、検証用のソース。

<!DOCTYPE html>
<html lang="ja">
<head>
  <title>jQuery .live and .bind</title>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
  <script>
    $(function(){
      $('*').bind('click', function(){ $('pre').append('bind: ' + this.tagName + '\n'); });
      $('a').live('click', function(){ $('pre').append('live: ' + this.tagName + '\n'); });
    });
  </script>
</head>
<body>
  <div><a href="#">[click!]</a></div>
  <pre></pre>
</body>
</html>

2. 実行結果

検証用のHTML上で[click!]の部分(a 要素)をクリックすると次のように出力される。環境は Windows 7 + Firefox 3.6。

bind: A
bind: DIV
bind: BODY
bind: HTML
live: A

つまり、bind()でバインドされたイベントのバブリングが全て完了してから、live()でバインドしたイベントが処理されていることになる。

3. 問題点

例えば、同じHTMLで次のようにイベントを設定した場合を考える。

$('body').bind('click', function(){ alert('Hello World!!'); });
$('div').bind('click', function(event){ event.stopPropagation(); });
$('a').live('click', function(){ alert('Hello jQuery!!'); });

期待する動作は

  1. a 要素の click イベント処理(「Hello jQuery!!」のアラート)
  2. div 要素の click イベント処理 (イベントのバブリング停止)
  3. body 要素の click イベントは発生しない。

だが、実際には

  1. div 要素の click イベント処理 (イベントのバブリング停止)
  2. body 要素の click イベントは発生しない。
  3. a 要素の click イベントは発生しない。

となる。その結果、期待する a 要素のイベントが発生せずにハマることになる。実際、数十分がこれで消費された……。