イベント処理とは
JavaScript では、Webページ上でイベントが発生したときにあらかじめ登録しておいた処理を実行させられる。イベント発生時に実行される処理や関数をイベントハンドラと呼ぶ。
イベントには、Webページ上でのマウス操作、キーボード操作、Webページ読み込み完了などがある。イベントの一覧は、HTML Standardにまとめられている。
イベントハンドラーの登録
イベントハンドラーの登録には、大きく2つの方法がある。
DOMで取得した要素のプロパティに登録する
下のように、DOMで要素ノードを取得し、取得したノードのプロパティに、イベントハンドラを設定する。イベントハンドラを無名関数やアロー関数を使って書くことも可能。
<input type="button" value="button" id="xxx">
<script>
let button = document.getElementById('xxx');
button.プロパティ = イベントハンドラ;
</script>
addEventListner
メソッドでイベントリスナーを登録する上記メソッドを用いてイベントに対して登録した関数をイベントリスナーと呼ぶ。
<input type="button" value="button" id="xxx">
<script>
let button = document.getElementById('xxx');
button.addEventListener = ('click', コールバック関数);
</script>
DOM要素のプロパティに登録する場合との違いは、プロパティの方のコールバックは1つしか登録できないが、addEventListner
では複数のイベントリスナーを登録できる。
イベントが発生すると、登録した順にイベントリスナーが呼ばれる。
<input type="button" value="button" id="xxx">
<script>
function dispHello(){
console.log('Hello');
}
function dispBye(){
console.log('Bye');
}
let button = document.getElementById('xxx');
button.addEventListener('click', dispHello);
button.addEventListener('click', dispBye);
</script>
HTML要素の属性として登録する方法もあるが、推奨されていない方法なので、詳細は割愛。コード的には、次のようなもの。
<input type="button" value="button" onclick="console.log('Hello')">
イベントハンドラの記述位置
HTMLからDOMツリーを構築するとき、HTMLの先頭から解析していくが、script
タグがあると解析を中断して、JavaScript を実行しようとする。
DOMツリーは完成していない状態のため、script
タグ内から未定義の属性を参照しようとすると実行エラーを起こす。
よって、JavaScript のコードを書く時には次のことに気をつける。
JavaScript のコードを HTML ページの末尾に記述する
最後(
</bod>
の直前)に書いておけば、DOMツリーは出来上がっているので問題にならないDOMContentLoaded イベントを利用する
DOMContentLoaded イベントは、DOMツリーが完成した時に発生するイベント。イベントリスナー登録で、このイベントを指定することで、DOMツリーが完成した後に登録されるようになる。
<script>
document.addEventListener('DOMContentLoaded', function(){
let button = document.getElementById('xxx');
button.addEventListener('click', function(){
console.log('Thank you');
});
});
</script>
load イベントを利用する
DOMツリー完了後にDOMContentLoaded イベントが発生する。その後、画像やスタイルシート等の全リソース読み込みが完了すると、load イベントが発生する。
イベントリスナーではなく、要素ノードのプロパティとしてイベントハンドラを登録する時に、次のようにして利用することができる。
<script>
window.onload = function(){
let button = document.getElementById('xxx');
button.onclick = function(){
console.log('How are you?');
};
};
</script>
script タグで defer 属性を設置する
script タグにて外部ファイル読み込み時にのみ利用できる。 defer 属性が設定された script タグでは、すぐに実行されるのではなく、DOMツリー構築後の DOMContentLoaded イベントが発生する直前に実行される。
イベントを受け取る
イベントハンドラやイベントリスナーが呼び出された時、そのトリガとなったイベントを引数で受け取ることができる。
受け取れる情報は、Event - Web API | MDNにまとめられている。書き方として、次のような形。
<input type="button" value="button" id="xxx"> <script> let button = document.getElementById('xxx'); button.addEventListener('click', function(event){ console.log('type :' + event.type); //=> click }); </script>
イベントの伝搬
HTMLページ内の要素で何らかのイベントが発生すると、当該要素にのみイベントが発生するのではなく、その親要素にもイベントが伝搬する。
あるイベントが発生すると、次のフェーズにおいて、経路上にある要素やオブジェクトに対して、同じイベントが発生する。
キャプチャリングフェーズ
イベント発生時に、発生ノードまでDOMツリーを辿っていくフェーズ。addEventListener メソッドで設定されない限り、イベントは発生しない。
ターゲットフェーズ
実際にイベントが発生した要素でイベントが発生するフェーズ。
バブリングフェーズ
キャプチャリングフェーズの反対で、発生ノードから上位のノードまでDOMツリー上に辿るフェーズ。
イベントの種類
大雑把に取得できるイベントは次のようなグループに分けられそう。
- マウス系
- キーボード系
change
イベントinput
イベント- コピペ系
- データ読み込み系
- その他
マウス系
マウス系はマウス操作に関するイベントで、次のように細分化できる。
- クリック
- ダブルクリック
- ボタンを立ち下げ時
- ボタンを立ち上げ時
- マウスが要素上を移動した時
- マウスが要素上に来た時
- マウスが要素上から離れた時
クリック、ボタン立ち下げ、ボタン立ち上げは、よく似た状態だが、イベントとしては『立ち下げ⇨立ち上げ⇨クリック』の流れで発生する。
クリック間隔が短い時は、連続した動作として認識され、連続回数が計算される。よって、ダブルクリックもクリックを短い間隔で実行した時に認識される。
その他にも、MouseEvent
オブジェクトではイベント発生時のマウス座標や、キー情報(Alt
, Ctrl
, Meta
, Shift
)も参照できる。
キーボード系
キーボード系はキーボード操作に関するイベントで、次のように細分化できる。
- キーを押している時
- キーを離した時
キーを押したままの状態にすると、イベントも連続して発生し続ける。その場合、KeyboardEvent.repeat
プロパティが true
になる。
キー立ち下げ時のみにしたい場合には、次のようなコードにする。
<textarea id="memo"></textarea> <script> function keyDown(event){ if (!event.repeat){ console.log('KeyDown code:' + event.code); } } let textarea = document.getElementById('memo'); textarea.addEventListener('keydown', keyDown); </script>
KeyboardEvent
オブジェクトでは、押されたキーやキーの文字などを参照するためのプロパティが用意されている。
change イベント
change
イベントは、上記がユーザ操作によって変更が確定されたときに発生する。
change
イベントはさらに次のように細分化できる。
- フォーム(
input
要素) - 選択メニュー(
select
要素) - テキストエリア(
textarea
要素)
input イベント
change
イベントに似ているが、input
イベントでは入力の度にイベントが発生する。
input
イベントはさらに次のように細分化できる。
- フォーム(
input
要素) - 選択メニュー(
select
要素) - テキストエリア(
textarea
要素)
また、InputEvent
オブジェクトでは入力された文字の値を逐次取得できる。
コピペ系
コピペ系は、要素でコピペ操作をした時に発生するイベントで、次のイベントに細分化できる。
copy
イベントpaste
イベントcut
イベント
それぞれイベントが設定されている要素ノードに上で、コピペ操作を行うとイベントが発生する。
データ読み込み系
データ読み込み系は文字通り、データ読み込みに関するイベントで、次のように細分化できる。
- ページ読み込み完了時(全リソース読み込み完了)
- DOMツリー構築完了時
ページ読み込みとDOMツリー構築では、DOMツリー構築の方が先に完了するため、イベントの呼び出し順は『DOMツリー構築完了⇨ページ読み込み完了』となっている。
HTMLページに含まれる要素に対しての処理は、DOMツリー構築完了時で良いが、画像に関する処理などはページ読み込み完了時が適切。
その他
そのほかにも次のイベントがある。
- 現在ページから他ページに遷移される直前
- ウィンドウサイズが変更される時