今回はフロントエンド開発の時に良く実装されるクリックイベントについて話をしていきます。
このボタンを押したらクリックしたら、表示を切り替えたいなー
ここの部分一回クリックしたら2回目以降はクリックできないようにしたいなー
上記以外にも、特定の要素をクリックしたら「こういう動きつけたいなー」などと思っている方も多いのではないでしょうか?
今回の記事ではクリック処理をこれから初めて実装する人に向けて「イベント」の基本から、実際にWebページ開発でよく使われるイベントである「クリック」についてサンプルコードを交えて説明します。
- イベントとは
- addEventListenerでイベントを登録する
- 開発によく使われるクリック処理3パターン
「クリック」イベントの実装サンプルだけ参考にしたい方は一番最後の項目である「開発によく使われるクリック処理3パターン」まで飛ばして読んでいただけたらと思います。
目次
イベントとは
今回の話は主に「クリック(click)」について解説していきますが、その前に理解しておきたい「イベント(event)」という概念について説明します。
フロントエンド・バックエンド問わず、Web開発をしていると「イベント」という言葉を耳にします。
フロントエンドの場合のイベントとは次のものになります。
- マウスをクリックする
- マウスを動かす
- Webページのスクロールする
- キーボードを打ち込む
- ブラウザサイズを変更する
- Webページの読み込みが終わる
上記のイベント例以外にも20を超えるイベントが存在します。
このイベント例を元にイベントとは何かを定義すると、大きく分けて次の2種類に分けられます。
- ユーザー起因による操作: マウス操作やキーボード操作など
- ブラウザ起因による動作: Webページの読み込み完了、画像の読み込み完了など
この「イベント」という概念を理解すれば次に説明する「addEventListener」の理解がしやすいかと思います。
addEventListenerでイベントを登録する
前回の章で説明したイベントを追加するためには、「addEventListener」というものを使います。
言葉から意味を理解する
言葉の意味から理解すると頭にスッと入ると思うので、まずはそれぞれの単語を分解して意味を確認しましょう。
- add(追加する)
- Event(イベント(クリックやファイル読み込み完了など))
- Listener(リスナー(イベントを検知した時に実行する処理))
「add」と「Event」に関しては名前から意味を推測することは出来ますが、最後の「Listener」とは何を表しているでしょうか?
ここでいう「Listener」とは、「処理そのもの」を指しています。
「addEventListener」を訳すと「イベント処理を追加する」という意味になります。
addEventListenerに必要なもの
「addEventListener」を使うためには最低限次の3つが必要です。
- Eventターゲット
- イベントの種類
- イベントが検知されたときに実行する処理
上記の3つ以外にセット出来るものは、以下ドキュメントの「options」になります。
しかし、「options」に関しては利用する場面が少ないので今回は割愛しますが、別の記事で解説する予定です。
Eventターゲット
EventターゲットになるものはDOMや、ブラウザのWindowオブジェクトなど様々です。
- DOM(Document Object Model) : ボタン・画像・文字などをJavaScriptで操作できるようにHTML要素
- Windowオブジェクト : DOM含め、その他にもconsoleやalertなどブラウザが提供している機能を保持するオブジェクト
イベントの種類 (click, load など)
「イベントの種類」はその名通り、「click」「load」「mousemove」など「イベントの名前」になります。
どんなイベントが利用できるかは「MDNのEvent.addEventListener()」のドキュメントページ画面左にある「イベント」の項目から確認することが出来ます。
イベントが検知されたときに実行する処理
「イベントが検知されたときに実行する処理」とは「関数(function)」のことです。
addEventListenerの使い方
- Eventターゲット : (DOM, Windowオブジェクト)
- イベントの種類 : (click, load, mousemove)
- イベントが検知されたときに実行する処理 (関数(function))
それでは先程お話した必要な3つ項目を使って「addEventListener」をどのように使うかコードを使って説明します。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <h1 id="click-target">これはh1要素です</h1> <script src="./main.js"></script> </body> </html> |
1 2 3 4 5 6 7 8 9 10 11 |
// h1の要素をEventTargetとする const clickTarget = document.getElementById('click-target'); // リスナー(=コールバック関数)には「無名関数」をセットしている。 // イベントによって実行されるコールバック関数は引数に「Event」オブジェクトを渡す。 clickTarget.addEventListener('click', (event) => { // event.targetでクリックした対象のDOMが取得できる。 // 今回は「h1」要素をクリックしたので「event.target = h1のDOM」となる。 const text = event.target.innerText; alert(text); }); |
上記コードを実際に実行した結果
2つ目のサンプルコードがJavaScriptのコードになります。
JavaScriptのコードの2行目で「EventTarget」を取得しています。今回の場合は「h1」要素を「EventTarget」としました。
次に6行目で「addEventListener」を使って「EventTarget」をクリックしたときの処理をセットしています。
「addEventListener」の引数は次のようになります。
- 第1引数にはイベントの種類をセット。今回の場合は「click」をセットした。
- 第2引数にはリスナー(イベントが検知されたときに実行する処理=関数)をセット。
サンプルコードのコメントにも書いていますが、「リスナー」=「コールバック関数」となります。そして、今回のコールバック関数には「無名関数」を使っています。
「コールバック関数」「無名関数」については別記事で説明しているので、以下の記事を参考にしていただけたらと思います。
上記のサンプルコードの内容を元に、addEventListenerの使い方をまとめると以下のようになります。
①Eventターゲット.addEventListener(②イベントの種類, ③イベントが検知されたときに実行する処理)
実行結果を示したアニメーション画像を確認していただくと、h1要素をクリックした時に、アラートが表示されているのがわかるかと思います。
それは10行目にて「alert」メソッドを実行しているからです。
この「alert」は「③イベントが検知されたときに実行する処理」の中で定義されているので、クリックした時にアラートが実行されるのです。
開発によく使われるクリック処理3パターン
今までの章で「addEventListener」の使い方について説明してきました。
ここからは実際に開発でよく使われるクリック処理のパターン3つをサンプルコードを交えて解説していきます。
クリック時に実行したい関数に正しい引数をセットしたい
次のサンプルコードで、「正しい使い方」「誤った使い方パターン1」「誤った使い方パターン2」の3種類を用意しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
// h1の要素をEventTargetとする const clickTarget = document.getElementById('click-target'); function receiveNumber(number) { console.log('受け取った数値は' + number + 'です。'); } // 正しい使い方: // リスナー(=コールバック関数)内から意図した値(今回の例だと数値)をセットしてreceiveNumberを実行している。 clickTarget.addEventListener('click', (event) => { const number = 1; // 説明として1をセットしているだけで、1という値に特に意味は無い receiveNumber(number); // receiveNumber関数に数値を渡す。 }); // 誤った使い方パターン1: // リスナーにコールバック関数を直接セットする代わりに既に定義している関数名をセットする // // 問題点: // - addEventListenerで実行される関数にはEventオブジェクトが渡される。 // - しかし、receiveNumberは数値(number)を引数に受け取る関数である。 // - Eventとnumberで期待しているデータが異なるため不具合が起きる clickTarget.addEventListener('click', receiveNumber); // 誤った使い方パターン2: // リスナーに実行する形式でreceiveNumberをセットする。(「receiveNumber(1)」は関数を実行している) // // 問題点: // - この場合addEventListenerには「undefined」がセットされるのでEventターゲットをクリックしても何も処理が実行されない。 // - 「undefined」がセットされる理由は「receiveNumber」には返り値がないため。(return が無い) clickTarget.addEventListener('click', receiveNumber(1)); |
今回のサンプルコードのシナリオは次のとおりです。
- イベントターゲットがクリックされたら「receiveNumber」関数を実行したい
- receiveNumber関数には数値の「1」を渡したい
まずは8行目の「正しい使い方パターン」から説明します。
10行目のaddEventListenerの第2引数であるリスナーには「receiveNumber」関数をセットしておらず、無名関数をセットしています。
そして、無名関数内で「receiveNumber」関数を実行しています。
なぜ「addEventListener」の第2引数に直接「receiveNumber」をセットしなかったのでしょうか?
その答えは15行目の「誤った使い方パターン1」のコメント内容を読むとわかります。
「addEventListener」の第2引数にセットされるリスナー(=コールバック関数)は引数にEventオブジェクトを受け取ります。
そのため、もし直接「receiveNumber」関数を「addEventListener」の第2引数に渡してしまうと、「receiveNumber」は数値ではなくEventオブジェクトを受け取ります。
それでは24行目の「誤った使い方パターン2」はどうでしょうか?
こちらは「receiveNumber」関数を実行した結果をセットしているので、今回の場合だと「undefined」がセットされます。
そのためイベントターゲットがクリックされても何も実行されることはありません。
これら2つの誤った使い方は初心者がよく陥るミスになるので気をつけましょう。
1回しかクリックできないボタンを作る
正しい使い方パターンと誤った使い方パターンの2つに分けてサンプルコードを使って説明していきます。
まずは誤った使い方パターンから。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// h1の要素をEventTargetとする const clickTarget = document.getElementById('click-target'); // 誤った使い方: // // - addEventListener, removeEventListenerそれぞれで第2引数に「clickOnce」関数を定義する。 // - それぞれ別々のコールバック関数として定義されているので同一関数として見られない // - 1つ目のaddEventListenerは削除されない clickTarget.addEventListener('click', function clickOnce(event) { alert('1回しかクリックできない!') }); clickTarget.removeEventListener('click', function clickOnce(event) { alert('1回しかクリックできない!') }); |
まず「addEventListener」で登録したリスナーは「removeEventListener」というメソッドを使って削除します。
使い方は基本的に「addEventListener」と同じで以下のようになります。
- 第1引数にはイベントの種類をセット。今回の場合は「click」をセットした。
- 第2引数には「addEventListenerでセットした」リスナーをセット。
第2引数の「addEventListenerでセットした」リスナーが「removeEventListener」のキモとなります。
上記サンプルコードの9行目と12行目で「addEventListener」「removeEventListener」のそれぞれの第2引数に「clickOnce」関数をセットしています。
しかし「clickOnce」関数は「addEventListener」と「removeEventListener」で別々でコールバック関数として定義しているので、異なる関数となります。
そのため、removeEventListenerが意図したとおりに動かず何回もクリック時の処理が実行されてしまいます。
実行結果は次の画像のとおりです。
それでは次に正しい使ったときのコードを確認しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
// h1の要素をEventTargetとする const clickTarget = document.getElementById('click-target'); // 正しい使い方 // // - addEventListenerもremoveEventListenerも同一の「clickOnce」関数を第2引数のリスナーとしてセットしている function clickOnce(event) { clickTarget.removeEventListener('click', clickOnce); alert('1回しかクリックできない!') } clickTarget.addEventListener('click', clickOnce); // こちらも正しい使い方 // コールバック関数に無名関数ではなく、関数名をつけてremoveEventListenerでも同じ関数(clickOnce)を参照できるようにしている。 clickTarget.addEventListener('click', function clickOnce(event) { // removeEventListenerはaddEventListenerで追加した処理を削除する // ドキュメント: https://developer.mozilla.org/ja/docs/Web/API/EventTarget/removeEventListener clickTarget.removeEventListener('click', clickOnce); alert('1回しかクリックできない!') }); |
「removeEventListener」を正しく使ったサンプルコードの場合は、clickOnceという関数を1つだけ用意しました。
「addEventListener」「removeEventListener」でこの同一の「clickOnce」関数を参照しています。
一度クリックした場合「removeEventListener」が実行されて、2回目以降のクリックは実行されません。
上記サンプルコードの実行結果は次の画像のとおりです。
1回クリックしたら一定期間クリックできないボタンを作る
最後に一定の時間クリック処理を無効にするやり方をサンプルコードを使って説明します。
この機能が使われる場面は、非同期通信を使うところが考えられます。(例えばTwitter、Facebookのタイムラインの続きのデータを取得するなど。)
非同期通信が開始したときは一連の処理が終わるまでは、クリックイベントを無効にしたい場面がよくあります。
それでは次のサンプルコードを確認してみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
// h1の要素をEventTargetとする const clickTarget = document.getElementById('click-target'); // 非同期通信などで一連の通信が完了するまで、クリックイベントを無効化したいときに使える手法 let canClick = true; clickTarget.addEventListener('click', function (event) { // canClickがfalseのときはここで処理を中断する if (!canClick) { return; } // canClickをfalseに変更して、2秒後にcanClickをtrueに戻す canClick = false; setTimeout(() => { canClick = true; console.log('2秒たった'); }, 2000); alert('2秒間クリックできなくなりました') }); |
サンプルコードでは「setTimeout」メソッドを使って擬似的に非同期通信を再現しました。
上記のコードでは「canClick」というフラグを使って、クリック時の処理を最後まで実行するか途中で中断するか判断しています。
今回の例だと、一度クリックしたらcanClickフラグをfalseにしており、2秒後にフラグをtrueに戻すことで2秒間ボタンが効かない時間を作っています。
サンプルコードの実行結果は次の画像のとおりです。
まとめ
ここまで、フロントエンド開発でよく使われるクリック時の処理を実装するために必要な知識を説明していきました。
今回の内容をまとめると次のとおりです。
- Web開発には「イベント」という概念が重要
- 「イベント」の種類の1つに「クリック(click)」がある
- 「addEventListener」という機能を使ってクリック時の処理を登録する
- 開発でよく使われるクリック処理の3パターンを解説した
もし今回の記事が「役に立った」「参考になった」と思っていただけたらシェアしていただけると泣いて喜びます!