CHAPTER6:Events

久しぶりにResig本読んだ。
Javascriptのイベントの仕組みについては十分理解していたつもりだけど、意外といろいろ新しい発見があった。

Javascriptのイベントについて

Javascriptではスレッドが1つしかない。
なので、ある処理を実行している間に発生したイベントはその処理が完了するまで待たされる。

イベントの伝達

そのイベントには「キャプチャリング」というフェーズと「バブリング」というフェーズがある。
以下のようなHTMLが合った場合に<a>でイベントが発生したとする。そうすると、イベントは<body>, <div>, <ul>, ... と上位のノードから下位のノードに伝達され最終的に<a>まで伝わる。これが「キャプチャリング」のフェーズ。

<body>
  <div>
    <ul>
      <li>
        <a href="#">.... </a>

<a>でのイベントハンドラの処理が行われた後は、今度は逆に<li>, <ul>, ... <body>という順番にイベントハンドラが呼び出される。これが「バブリング」のフェーズ。

Eventオブジェクトについて

W3C標準の方式とIE固有の方式で異なる。

  • W3C標準:イベントハンドラの引数として渡される。
  • IE固有:グローバルなwindowオブジェクトのeventプロパティに格納される。

以下のようなイディオムで両方に対応できる。

hoge.onkeypress = function(e) {
  e = e || window.event;
  alert(e.keyCode);
}

イベントハンドラ内でのthisについて

イベントハンドラ内でthisを参照すると、そのイベントが発生した要素(オブジェクト)を参照することが出来て便利。ただし、IEにおいて、イベントハンドラの定義方法によってはthisの扱いが異なるので注意する必要あり。(後述)

ブラウザのデフォルトの動作をオーバーライドする

ブラウザでイベントが発生したとき、以下のような順番で処理が行われていく。

  • キャプチャリング
  • バブリング
  • ブラウザのデフォルトの動作

なので、バブリングの途中でイベントの伝達を止めてしまえば、そのイベントに対するブラウザのデフォルトの動作は発生しなくなる。

その方法はW3C標準とIEとで異なる。(eはイベントハンドラに渡されたeventオブジェクトとする)

  // e is evetn object
  // W3C
  e.preventDefault();

  // IE only
  window.event.returnValue = false;

イベントを割り当てる3つの方法

古典的な方法

'on〜'というプロパティを使う。

hoge.onclick = function(e) {
  ...
};

利点:

  • ほとんどのブラウザでサポートされている
  • thisキーワードでその要素自身を参照することができる。

欠点:

  • イベントのバブリングにしか対応しておらず、キャプチャリングの制御ができない。
  • 1つしかハンドラを登録できない。
W3C標準

addEventListener()メソッドを使う。

hoge.addEventListener('click', function(e) {
  ...
}, false);

利点:

  • キャプチャリングとバブリングをサポートしている。
  • 1つの要素に複数のイベントハンドラを登録することができる。
  • thisキーワードでその要素自身を参照することができる。

欠点:

  • IEでサポートされていない。
IE固有の方法

attachEvent()メソッドを使う。

hoge.attachEvent('onclick', function() {
  ...
});

利点:

欠点:

  • IEしか対応していない。
  • thisがwindowオブジェクトを参照していて混乱の元。
  • イベントのバブリングにしか対応しておらず、キャプチャリングの制御ができない。
解決策

Dean Edwards さんという人が書いたaddEvent()を使えば解決すると言ってる。
以下のリンク参照:
Dean Edwards: addEvent() - My Solution

ほかに気をつけること

  • domオブジェクトが参照できることをチェックする。例)if ( document && document.getElementById )
  • タグの属性にコードを埋め込まない。ダメな例)<a href="#" onclick="doHoge()">
  • javascriptが無効になっていてもナビゲートできる作りにする