■ソース
以下のコードをHTMLのスクリプトの一番最初に記述する(読み込む)
function addListen(elm, type, func){ if(!elm){ return false; } if(elm.addEventListener){ elm.addEventListener(type, func, false); } else if(elm.attachEvent){ elm.attachEvent('on' + type, func); } else{ return false; } return true; }
でも、もっと素敵なコードは以下のようになる。ブラウザ判定は1回あれば十分なのでロード時に実装に合わせた関数が定義される。
var addListen = (function(){ if(window.addEventListener){ return function(elm, type, func){ elm.addEventListener(type, func, false); } } else if(window.attachEvent){ return function(elm, type, func){ elm.attachEvent('on' + type, func); } } else{ return new Function(); } })();
■解説
- addListenの引数のelmには要素(windowやdocument.getElementById(‘id_name’))を、typeにはイベントの種類(loadやclickなど、イベントハンドラからonをはずしたもの)を文字列として、funcにはイベント発生時の処理する関数を渡す
- addEventListener()はIEには実装されていないので、IEは実装されているattachEvent()を使う必要があり、条件分岐している
- addEventListener(type, func, false)の第三引数には「true」もしくは「false」が入り、どのフェーズでイベントが実行されるかを指定する
- IE用の記述、attachEvent(‘on’ + type, func)の第一引数はイベントハンドラと同じスペルの文字列で指定する。なおIEには後述するキャプチャー・フェーズが存在しない
■例
以下のようにすると、ロード時にアラートが実行される。
<script type="text/javascript"> function addListen(elm, type, func){ if(!elm){ return false; } if(elm.addEventListener){ elm.addEventListener(type, func, false); } else if(elm.attachEvent){ elm.attachEvent('on' + type, func); } else{ return false; } return true; } addListen( window, "load", function(){ alert('test'); } ); </script>
■では特定の要素にイベントリスナを使うには…
以下のようにしたいが、このままヘッド内に記述するとエラーが起こる。
addListen( document.getElementById('test'), "click", function(){ alert('test'); } );
実行される時点ではドキュメントオブジェクトは存在しないためである。これを解決するためには…
addListen(window, "load", init); function init(){ addListen( document.getElementById('test'), "click", function(){ alert('test'); } ); }
とするか、グローバル空間を節約したいなら、以下のように書いてみるのもイイかもしれない。
addListen( window, "load", function(){ addListen( document.getElementById('test'), 'click', function(){ alert('test'); } ); } );
但し、最後のコードはIEでメモリリークが起こるらしい。
■メリット
- イベントハンドラでは同要素に対する特定の指定は1回しか記述できないが、イベントリスナを使った場合は何回でも可能である。これはライブラリやフレームワークを使ったり、分業してスクリプトを書いている場合に非常に有用である
- HTML内の<body onload=”alert(‘test’)”>とwindow.onloadが衝突したりする事が無い
■おまけ(フェーズについて)
W3C DOMイベントモデルにおいてイベントは外側のBOXから指定の要素に伝わって行き(この段階がキャプチャーフェーズ)、ターゲットに届いたら、一番外側のBOXに戻る(この段階がバブリング・フェーズ)