addEventListener の第三引数について

addEventListenerはよく使うけど、第三引数の true | false の意味は良く分かってなかった。

void addEventListener ( String type , EventListener listener , boolean useCapture )

This method allows the registration of event listeners on the event target.If an EventListener is added to an EventTarget while it is processing an event, it will not be triggered by the current actions but may be triggered during a later stage of event flow, such as the bubbling phase.

If multiple identical EventListeners are registered on the same EventTarget with the same parameters the duplicate instances are discarded. They do not cause the EventListener to be called twice and since they are discarded they do not need to be removed with the removeEventListener method.

Arguments:
type: The event type for which the user is registering
listener: The listener parameter takes an interface implemented by the user which contains the methods to be called when the event occurs.
useCapture: If true, useCapture indicates that the user wishes to initiate capture. After initiating capture, all events of the specified type will be dispatched to the registered EventListener before being dispatched to any EventTargets beneath them in the tree. Events which are bubbling upward through the tree will not trigger an EventListener designated to use capture.

英語じゃ良く分かんねー。ってことで幾つかテストしてみた結果報告ですよ。

やってみた感じ、イベントを優先的に受け取れるみたい。通常、イベントは発生した要素から順に親要素へ伝播する。下記のような場合、ボタンをクリックすると、button要素から親のdiv要素へイベントに対するそれぞれの動作が実行される。

┌ div─────┐
│       │
│ button   │
│       │
└───────┘
<div><button>click</button></div>

しかし、これは第三引数(useCapture)がfalseだった場合のこと。trueのものがあった場合、それが優先される。じゃあtrue同士の場合はどうなるかというと、親が優先される。
つまり、下記のような順番で処理されるようだ。

  1. 親のtrue
  2. 子のtrue
  3. 子のfalse
  4. 親のfalse

因みに要素中にonclick等で入れた動作はfalseの状態。

<div id="captureModeContainer1">
  <div id="captureModeContainer2">
    <button id="captureModeButton" onclick="alert('Button Clicked')">Click !!</button> 
  </div>
</div>
var container1 = document.getElementById('captureModeContainer1');
container1.addEventListener('click',function(){
    alert('Container1 Clicked !!');
},false);
var container2 = document.getElementById('captureModeContainer2');
container2.addEventListener('click',function(){
    alert('Container2 Clicked !!');
},true);

この様なコードの場合、ボタンをクリックすると以下のような順番でアラートが表示される。

  • Container2 Clicked !!
  • Button Clicked
  • Container1 Clicked !!

つーことで、報告終わり。

追記(2007-02-02)

通常、DOMのイベントモデルでは、発生したイベントは「イベントが発生した要素」からその祖先要素へと順番に伝搬していき、イベントハンドラやイベントリスナは、それらが設定された要素のところまでイベントが昇ってきた段階で初めて動き出す。これをイベントの伝搬とかバブリングとか言うんだけど、XBLでphase="capturing"という指定を使ったり、addEventListener()メソッドの第3引数にtrueを渡したりすると、そのイベントハンドラ(リスナ)には特別なルールが適用されて、イベントが発生した瞬間、バブリングを待たずにイベントを処理できるようになる(イベントのキャプチャリング)。

XBL絡みだけどpiro氏も解説してた。しかし、piro氏の"Split Browser開発"話は参考になるものが多くて助かるなぁ。