解 説

addEventListenerとは

イベントハンドラは同一の要素あるいは同一のイベントに対して複数のイベントハンドラを定義できないのですが、イベントリスナを使うと有利な事は同一の要素あるいは同一のイベントに対して複数のイベントリスナを関連付けられるのです。また一旦設定したイベントリスナを削除できる点にあります。一方イベントリスナとして一般的なaddEventListenerがIEに対応していないなどの問題があります。

addEventListener の書き方は次のとおりです。

target.addEventListener(type, listener , useCapture);

type:イベントの種類
listener:リスナー関数
useCapture:true を指定した場合はCaptureフェーズ。falseを指定した場合はBubblingフェーズ。省略した場合は false となります。

addEventListener() の第3引数

addEventListener() の第3引数でイベントを受け取るタイミングを指定することができます。

  1. Captureフェーズ: Documentオブジェクトからイベントが発生したオブジェクトに向かって各要素をたどっていき、順にリスナ関数の処理を行っていきます。
  2. Targetフェーズ: イベントが発生したオブジェクト上のリスナ関数の処理を行います
  3. Bubblingフェーズ: イベントが発生した要素から親要素に向かい、ルートオブジェクトにたどり着きます。順番にリスナ関数の処理を行っていきます。

bubble
addEventListener()の第3引数であるuseCaptureの設定によって、以下のようにイベントをどのフェーズで行うかを指定することができます。

  • true: Captureフェーズ
  • false: Targetフェーズ, あるいは Bubblingフェーズ

実際にサンプルで見てみましょう。

CSSソース

HTMLソース

JavaScriptソースCaptureフェーズ

JavaScriptソースBubblingフェーズ

sample1 Captureフェーズ
sample2 Bubblingフェーズ

ポイントはdiv要素の id=”inner”とid=”outer”は親子関係にあり、子要素の id=”inner”をクリックすると子要素も親要素も両方ともクリックしたことになります。そしてもっとも解りやすい例として、第3引数でどちらの実行が先に行われるか設定できるものです。Captureフェーズなら親が先に実行され、 Bubblingフェーズなら子要素が先に実行されることになります。

また、 Event.stopPropagation() メソッドを呼び出すと、イベントの伝播をそこで停止して、以降のノードへの伝播を止めることができます。

たとえば、子要素でイベントが発生したとき第3引数のuseCaptureをtrueにしてCaptureフェーズとしておき、 Event.stopPropagation() メソッドを呼び出すことで、イベントの伝播をそこで停止して子要素まで届かなくすることができます。