ここでは JavaScript を いつどのタイミングで 実行するかを設定する方法について学習します。

この イベント処理 を学ぶことで ブラウザの利用者(閲覧者)の動作などをきっかけに JavaScript を実行することができます。

JavaScript Event Bubbling(イベント伝播)

何らかの動作をきっかけに発生したもの

マウスで 「クリック」 したとき、スマートフォンで 「タップ」 したとき、キーボードを 「押した」 とき、など様々な動作をきっかけに JavaScript を実行したい場合があります。

普段意識することはありませんが、この「動作」の後には必ず イベントが発生しています

クリックをすると「クリックイベント」、画面をスクロールしたら「スクロールイベント」が発生します。

このイベントを利用することで、利用者が 何らかの動作を行った ということをプログラムに伝えることができます。

例: 画面のどこかでクリックすると、クリックした場所の座標がこの下に表示されます。

イベントの種類

イベントには、ユーザーの動作 をきっかけに発生するイベントや、ブラウザ自身 が何らかの結果を元に発生するイベントなど、多くの種類があります。
ここでは代表的ないくつかイベントをご紹介します。

イベント名 種類 いつ発生するか
keydown キーボード 任意のキーが押されたとき
keyup キーボード 任意のキーが (押された状態から) 解放されるとき
click マウス タグ要素内でクリックして離された時
select マウス テキストが選択されている時
submit フォーム サブミットボタン(送信するボタンなど)が押されたとき
copy クリップボード 選択範囲がクリップボードにコピーされたとき
paste クリップボード クリップボードからアイテムが貼り付けられたとき
resize 画面(ビュー) 画面サイズが変更されたとき
scroll 画面(ビュー) 画面がスクロールされた時
load リソース リソースとそれに依存するリソースのロード(読み込み)が完了したとき

より詳しい イベントの種類 については イベントリファレンス | MDN でご確認いただけます。

イベントハンドラ / イベントリスナー

イベントはブラウザ自身が発生させているため、普段開発者が意識することは特にありません。

しかし、特定のイベントをきっかけに JavaScript を実行する必要がある(例: ボタンが押されたら送信する)場合にはこのイベントを利用します。

イベントハンドラ(リスナー)は、イベントをきっかけに処理を開始するプログラムのです。

これらには、動作が行われた後に処理を行う関数を登録することができます。

つまり、

イベントをきっかけに行いたい関数 を 予めイベントハンドラ(リスナー) に登録することで、
イベントが発生したら登録されているJavaScript を実行する

といった処理を実装することができます。

イベントハンドラ 登録の例

イベントハンドラには HTML要素 の属性で登録する方法と、JavaScript を使用して登録する方法があります。

HTML要素の属性で登録する方法

                    
<!-- buttonタグ要素の クリックイベントハンドラ onclick に 関数を登録します -->
<!-- 引数にグローバルオブジェクト(windowオブジェクトの)event オブジェクトを渡します -->
<button onclick="_onClickButtonFromHandler(event);">クリックミー!</button>
                    
                    
// クリックされた時に実行する関数を作成します
function _onClickButtonFromHandler(event) {
    console.log('handler', event);
}
                    
                

JavaScript で登録する方法

HTMLタグの idclass、タグの名前などをもとにJavaScript内でHTML要素を取得します。次の例では、document.getElementById関数を使用して、id をもとに HTML要素を取得しています。

                    
<button id="buttonHandler">クリックミー!</button>
                    
                    
// クリックされた時に実行する関数を作成します
function _onClickButtonFromHandler(event) {...}
// 関数を onclick ハンドラに 登録します
let buttonHandlerElement = document.getElementById('buttonHandler');
buttonHandlerElement.onclick = _onClickButtonFromHandler;
                    
                

イベントリスナー 登録の例

イベントリスナーには複数の関数を登録することができます。
特定の要素のイベントを処理したい場合はイベントハンドラでも構いませんが、window.onload のような グローバルなイベントに関数を関連付ける場合 は イベントリスナー を使用しましょう。


<button id="buttonListner">ボタンを押して!</button>
                    
                    
// 登録用の 関数その1 を作成します
function _onClickButtonFromListner_1(event) {
    console.log('listner 1', event);
}

// 登録用の 関数その2 を作成します
function _onClickButtonFromListner_2(event) {
    console.log('listner 2', event);
}

// DOMの準備が完了した場合に呼び出される window.onload に関数を登録します
window.addEventListener('load', function() {
    console.log('すべての文章が読み込まれ、DOMツリーが構築されました');
    // イベントリスナーを登録する対象となる要素を取得します
    let buttonElement = document.getElementById('buttonListner');
    // 要素に 関数その1 を登録します
    buttonElement.addEventListener('click', _onClickButtonFromListner_1, false);
    // 要素に 関数その2 を登録します
    buttonElement.addEventListener('click', _onClickButtonFromListner_2, false);
}, false);
                    
                

addEventListener の引数について

第1引数・・・どのイベントをきっかけにするか、イベントの種類を渡します。
第2引数・・・登録する関数を設定します。*実行してはいけません → ✕ _test()、◯ _test
第3引数・・・親子(要素)で同一のイベントを登録していた場合の、イベントの発生順序です。*通常は false でOKです

より詳しい addEventListener については EventTarget.addEventListener() – Web API | MDN でご確認いただけます。

イベントの伝播

伝播とは、伝わり広がって行くこと

ある特定の HTML要素 から発生したイベントは その親要素 でも発生するといった特徴があります。
ここでは「クリックイベント」を例に解説します。

ある要素がクリックされた場合、クリックイベントはその要素のハンドラ(リスナー)に登録されている関数を実行します。
しかし、これで終わりではなく、イベントはその親要素へ、またその親要素へと伝播します。

「子要素がクリックされた」は、つまり「親要素もクリックされた」ということになると考えれば分かりやすいと思います。

次の例では、内側の四角をクリックすると外側の 親要素の四角のイベントも実行される 動きを確認できます。

親要素の方向へ伝播する例


<!-- それぞれに onclick イベントを設定します -->
<div class="..." onclick="alert('「赤」色');">
    <div class="..." onclick="alert('「黃」色');">
        <div onclick="alert('「青」色');"></div>
    </div>
</div>
                    

伝播を止める 例

Eventオブジェクトの stopPropagation 関数 を実行することで、親要素への伝播を止めることができます。

もし同じ要素のイベントリスナーに複数のイベントが登録されている場合は、一つのイベントから他のイベントの伝播を止めることはできません。

また、必要な場合以外は伝播はなるべく止めない でください。これは予想外の箇所に影響が出る可能性があるからです。

次の例では、青色の四角をクリックすると黄色のイベントで 伝播を止める動きを確認できます。


<!-- 黄色の onclick イベントに 伝播を止める event.stopPropagation(); を追加します -->
<div class="..." onclick="alert('「赤」色');">
    <div class="..." onclick="alert('「黃」色');event.stopPropagation();">
        <div onclick="alert('「青」色');"></div>
    </div>
</div>
                    

イベントの発生元要素 と イベントの実行要素

Eventオブジェクトの target を使用すれば、イベント発生元の要素 について参照することができます。

また currentTarget を使用すれば、現在実行している要素 について参照することができます。

次の例では、Eventオブジェクトの 発生元の要素 target 現在実行されている要素 currentTarget の値を確認することができます。

                        
<!-- 黄色の onclick イベントに 伝播を止める event.stopPropagation(); を追加します -->
<div class="..." data-value="「赤」色" onclick="bubbling(event);">
    <div class="..." data-value="「黄」色" onclick="bubbling(event);">
        <div data-value="「青」色" onclick="bubbling(event);"></div>
    </div>
</div>
                        
                        
function bubbling(event) {
    alert('target: ' + event.target.getAttribute('data-value') + ', currentTarget: ' + event.currentTarget.getAttribute('data-value'));
}
                        
                    

課題

「課題1のボタンです」ボタンを押すと、id="count" の値 0ずつ増やすイベントハンドラを作成して、実行するプログラムを作成してください。


<!-- index.html にコピペして作成してください -->
<button>課題1のボタンです</button>
<div id="count">0</div>

「課題2のボタンです」ボタンを押すと、id=”hide” を非表示にするイベントリスナーを作成して、実行するプログラムを作成してください。

<!-- index.html にコピペして作成してください -->
<button>課題2のボタンです</button>
<div id="hide">押されたら消えます</div>
                
以下のコードは、親要素のdivタグ がクリックされたら data-value に設定されている 「Good morning」をコンソールに出力するプログラムです。 しかし、子要素のstrongタグ がクリックされた場合 は、この値を取得することができません。 この バグ を修正し、子要素をクリックした場合でも、あいさつを表示することが出来るように、修正してください。

<!-- index.html にコピペして作成してください -->
<div data-value="Good morning" 
  onclick="console.log('あいさつ', event.target.getAttribute('data-value'));">
  ここは親要素<strong>ここは子要素</strong>
</div>