Noise of Web Programming

主にHTML/CSS/JavaScriptやWebサービスの情報を配信しています。可能な限り実装方法まで書いていくつもりです。

ブログを移転しました。

Tecuration.com

このサイト同様、HTML/CSS/JavaScriptなどのフロントサイドWeb開発に関する最新情報やライフハックを配信しています。

HTMLからイベントハンドラを切り離す!救世主イベントリスナー

前回イベントハンドラについて書いた。

JavaScriptのイベントハンドラをまとめてみた


このイベントハンドラなのだがやや問題があり、今回紹介するイベントリスナーを使ったほうが良いということを学んだので、まとめてみる。

イベントハンドラをHTMLから切り離す


まずはこの点について。僕の意見としてはHTML内にJavaScriptを混ぜ込ませるというのが、何とも気持ち悪い。またHTMLコードが長くなると保守性も悪くなるだろう。というわけでイベントハンドラJavaScript部分に書けないかと思っていたところ、以下の記事を見つけた。

イベントハンドラをHTMLから分離する 基本サンプル


window.onloadを使い、HTML読み込み後にJavaScriptを実行することで要素へイベントをセットすることが出来る。例えばこんな感じ。

<script>
window.onload = function(){
  var e = document.getElementById('target');
  e.onclick = function(){ alert('Hi'); }
}
</script>
<input type="button" value="push" id="target">


これでHTMLからイベントハンドラを切り離すことに成功した!

JSでのイベントハンドラの問題点


...ところがJS内に書くイベントハンドラには問題点があることが分かった。一つのオブジェクトに同じイベントハンドラを複数セットできないのだ。以下にwindowオブジェクトへ複数のonloadをセットした例を書く。

// HTML
<head>
  <script src="a001.js"></script>
  <script src="a002.js"></script>
</head>

// a001.js(外部ファイル)
window.onload = function(){
  alert('Hi');
}

// a002.js(外部ファイル)
window.onload = function(){
  alert('Hi!!!!!!!!!!!!!');
}


この場合、どちらのJavaScriptが実行されるか...答えは後に読み込んだa002.jsであり、テンション高く"Hi!!!!!!"と表示される。つまり同じオブジェクトに対して同じイベントハンドラを複数セットしたので後者で上書いてしまったのだ。というわけで、window.onloadは万能ではないということが分かった。


救世主イベントリスナー現る


ここで知ったのが救世主イベントリスナーの存在。これひとつでHTMLからの分離、イベントハンドラの問題点は解決される。イベントリスナーでは、特定の要素(オブジェクト)で発生したクリックやマウスオーバーなどのイベントに対し、どんな処理をさせるかをセットすることが出来る。実際にコードを見てみよう。



第一引数 : イベント


第一引数のイベントはイベントハンドラ名から"on"をとったものになる。loadとかclickとかね。(イベントハンドラについてはこちらの記事を参照。)


第二引数 : 処理


第二引数の処理は上記のようにaddEventListener内に書いても良いし、関数を呼び出してもよい。1点注意。関数を呼び出す際は、括弧をつけずに関数名のみ記述しよう。

function func(){ alert('Hi'); }
e.addEventListener("click", func, false);
//                          ^^^^括弧をつけない


第三引数 : フェーズ


第三引数にはどのフェーズでこのイベントを実行するかを指定する。以下の記事がとても参考になる。

addEventListener()の第3引数の意味とかをちゃんと理解する為のメモ
JavaScript addEventListener()


true/falseに限らずこのイベントリスナーで注意しなければいけないことは、特定のイベントをセットした要素郡の親子関係。同じ"click"イベントをセットした要素が親子関係にあるとき、親要素をクリックしても子要素までイベントは伝播しないが、子要素をクリックすると親要素->子要素とイベントが伝播してしまう。ちなみにこれはイベントハンドラでも一緒。しっかり考慮してHTMLを組む、またはEvent.stopPropagation()とかいうのを使えばイベントの伝播をとめられるようだ。試してないのでわからない。


本題に戻り、window.onloadの代わりにどうやってイベントリスナーを使うかというと、以下の通り。

// HTML
<head>
  <script src="a001.js"></script>
  <script src="a002.js"></script>
</head>

// a001.js(外部ファイル)
window.addEventListener("load", function(){
  alert('Hi');
},false);

// a002.js(外部ファイル)
window.addEventListener("load", function(){
  alert('Hi!!!!!!!!!!!!!');
},false);


これで上書きが行われずに、a001.jsが実行された後に、a002.jsが実行されるようになる。めでたしめでたし!本当にイベントリスナーはありがたい。