DOM Events とブラウザの実装
2007-03-23


ブラウザ上でのイベント処理の仕組みは DOM 2 Events および DOM 3 Events 草案にて規定されています。しかし、DOM 2 Events で言及されていない部分など、細かい動作はブラウザごとに異なっていることもあります。そうした仕様と実装の差異を、「作って納得! DOM 2 Events」で触れなかったものも含めて、いくつかまとめてみました。

ターゲットフェーズで呼び出されるリスナ

DOM 2 Events のイベントモデルにおいて、あるノードでイベントが発生すると、そのノードの祖先ノードのイベントリスナが呼び出されるキャプチャリングフェーズ、そのノード自身のイベントリスナが呼び出されるターゲットフェーズ、再び祖先ノードのイベントリスナが呼び出されるバブリングフェーズと、3 段階にわたってイベントが伝播していきます。このうちターゲットフェーズでは、addEventListener メソッドで第 3 引数 useCapturefalse に指定して登録したイベントリスナのみが呼び出されることになっています。

Opera 9 はこれに従っていますが、Firefox 2 および Safari 2 ではターゲットフェーズにおいて、useCapturetrue に指定して登録したイベントリスナまでもが呼び出されてしまいます (参考: Mozilla Bug 235441)。なお、Safari はナイトリービルドにおいて一旦は仕様どおりの動作になったものの、Gecko との互換性を保つためにあえて以前の動作に戻したようです。

EventListener インターフェースを実装するオブジェクト

DOM 2 Events において、EventListener インターフェースを実装するオブジェクトは handleEvent メソッドを実装しなくてはいけません。しかし、これは Java のような、関数をファーストオブジェクトとして扱えない言語を考慮に入れてのことであり、付録の ECMAScript Language Binding によれば、ECMAScript では関数オブジェクトが EventListener インターフェースを実装することになっています。すなわち、関数を addEventListener メソッドの第 2 引数 listener などに直接渡せるということです。

ですが、Firefox 2 や Opera 9 では、関数オブジェクトでなくとも handleEvent メソッドを持つオブジェクトなら、EventListener インターフェースを実装するものとして扱ってくれます。Safari 2 では関数オブジェクトしか EventListener として使えませんが、Safari のナイトリービルドでは handleEvent メソッドを持つオブジェクトも EventListener として使えるようです。

var listener = {
  handleEvent: function (evt) { alert(this); },
  toString: function () { return "[EventListener implementation]"; }
};
// Click, and alerts "[EventListener implementation]".
// OK: Firefox 2, Opera 9, and maybe Safari 3
element.addEventListener("click", listener, false);

イベントの伝播におけるルートノード

あるノードでイベントが発生すると、キャプチャリングフェーズではルートノードから直近の親ノードまで、バブリングフェーズでは親ノードからルートノードまでのイベントリスナが呼び出されます。ここで、ルートノードというのは、通常は文書ノード (document) のことを指します。つまり、ある文書中の要素ノードでイベントが発生した場合、キャプチャリングフェーズは document から始まり、バブリングフェーズは document で終わるといった具合です。


続きを読む

[JavaScript]
[Web 関連技術]

コメント(全2件)
コメントをする


記事を書く
powered by ASAHIネット