概要
オブジェクトにイベントリスナーを登録する場合、対象オブジェクトの生成とリスナー登録の前後関係に留意しなければならない。
失敗例
まず失敗例。以下のコードはボタンをクリックしても動作しない。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <title>リスナー登録~失敗</title> <script> document.getElementById('button').addEventListener( 'click', (() => alert('clicked!')), false); </script> </head> <body> <button id ="button">Click Me!</button> </body> </html> |
なぜなら、head要素でbodyが読み込まれる前にid=”button”の要素を読み込もうとするが、その段階でまだ対象となるbutton要素は読み込まれていないからだ。
その後bodyでbutton要素が配置されるが、そのときにはリスナーを登録しようとして失敗しているので、結局button要素にはリスナーは登録されていない。
事実検証画面で確認すると、”Uncaught TypeError: Cannot read property ‘addEventListener’ of null”となっていて、リスナーを登録しようとしている要素がnullだとなっている。
改善例1~後置
以下は、button要素が配置された後にスクリプトを実行するように、script要素の位置を後ろに異動したもの。この場合はエラーにはならず、ボタンを押せば無事ダイアログが表示される。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <title>リスナー登録~後置</title> </head> <body> <button id ="button">Click Me!</button> <script> document.getElementById('button').addEventListener( 'click', (() => alert('clicked!')), false); </script> </body> </html> |
改善例2~onload
以下の例は、スクリプトをhead要素に置いたままで正常に実行する例。
リスナー登録の部分をwindow.onload
のリスナーとして定義することで、ページの読み込みが完了した後にwindow.onload()
が実行され、その内容としてリスナーの登録が行われる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <title>リスナー登録~後置</title> <script> window.onload = () => { document.getElementById('button').addEventListener( 'click', (() => alert('clicked!')), false); } </script> </head> <body> <button id ="button">Click Me!</button> </body> </html> |
この方法は、JSのコードを別ファイルとしてheadで読み込むような際にも有効。
改善例2’~windowリスナーの追加
もう一つの改善例は、windows.onload()
メソッドをオーバーライドする代わりに、window
にload
イベントに対するリスナーを追加するもの。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <title>リスナー登録~後置</title> <script> window.addEventListener('load', () => { document.getElementById('button').addEventListener( 'click', (() => alert('clicked!')), false); }); </script> </head> <body> <button id ="button">Click Me!</button> </body> </html> |
これは先のwindow.onload()のオーバーライドと同じ効果を持ち、ボタンには適切にリスナーが登録される。