クリックに反応する
このレッスンで分かること
addEventListenerは「どの要素で」「どの出来事が起きたら」「何をするか」の 3 つを結び付けます- 第 2 引数に渡すのは関数そのもので、
handler()と丸かっこを付けると動きません- HTML の
onclick属性ではなく、JavaScript 側で結び付けるのが今の書き方です
クリックに反応する とは
ボタンが押されたときにだけ動く処理を、要素とイベント名に結び付けて登録することです。
開いた瞬間の一度きり、から抜け出す
第8章で書いた JavaScript は、どれもページが読み込まれた瞬間に上から下まで走って、それで終わりでした。作品の配列から .work-card を描き終えたら、あとは何も起きません。見ている人がボタンを押しても、文字を打っても、画面は静まりかえったままです。
Web ページが「アプリらしい」と感じられるのは、この静けさが破れたときです。押したら開く、打ったら数が変わる、選んだら色が変わる。こうした反応をつくる仕組みが、イベント処理です。この章では、そこだけを扱います。
イベントとは、ブラウザの中で起きた出来事のことです。クリックされた、キーが押された、フォームが送信された、ページの読み込みが終わった。ブラウザはこうした出来事が起きるたびに「いま click が起きました」という知らせを出しています。私たちがやるのは、その知らせを聞いて動く処理をあらかじめ登録しておくことだけです。
知らせは、聞いている人がいなくても常に流れています。ボタンを押せば click イベントは必ず発生しています。何も起きないように見えるのは、その知らせを受け取る処理を誰も登録していないからです。イベント処理を書くのは「出来事をつくる」作業ではなく「すでに流れている出来事を拾う」作業だ、と考えると全体像がつかみやすくなります。
なお、この章の出発点は第8章の完成形そのものです。作品ギャラリーはデータから描かれたまま残っています。見た目が必要になる回では、その回の CSS に書かれた状態で渡します。みなさんが書くのは JavaScript と、ごく少しの HTML だけです。
addEventListener の 3 要素
登録に使うのが addEventListener です。
const helloButton = document.querySelector("#hello-button");
helloButton.addEventListener("click", function () {
console.log("押されました");
});読み解くと、3 つの部品でできています。
- 対象 …
helloButton。どの要素で起きた出来事を見るのか - 種類 …
"click"。どの出来事を待つのか。文字列で書く - 処理 … 第 2 引数の関数。出来事が起きたときに動く中身
日本語に直すと「helloButton で click が起きたら、この関数を動かして」となります。この 3 つがそろって、はじめて反応が生まれます。どれか 1 つでも欠けたり名前を間違えたりすると、エラーも出ないまま静かに何も起きません。イベント処理のつまずきの大半は、この「静かに何も起きない」に由来します。
種類は決まった名前を文字列で渡す
イベントの種類は、ブラウザがあらかじめ決めている名前を文字列で渡します。この章で扱うものは次の通りです。
| 種類 | いつ起きるか | 主な対象 |
|---|---|---|
| click | 要素が押されたとき | ボタン、リンク、どんな要素でも |
| input | 入力欄の値が変わるたび | input、textarea |
| change | 入力を終えて値が確定したとき | input、select |
| submit | フォームが送信されたとき | form |
| keydown | キーが押し下げられたとき | 入力欄、document |
"click" を "Click" や "onclick" と書いても、ブラウザは「そんなイベントは知りません」とは言ってくれません。ただ、一生起きないイベントを黙って待ち続けるだけです。打ち間違えやすいところなので、動かないときに最初に見る場所になります。
渡すのは関数そのもの
第6章で学んだコールバック関数が、いよいよ本当に効いてくる回です。addEventListener の第 2 引数は、あとで呼んでもらうための関数です。自分では呼びません。
// 正しい。関数そのものを渡している
helloButton.addEventListener("click", showMessage);
// 間違い。その場で呼んでしまい、戻り値のほうを渡している
helloButton.addEventListener("click", showMessage());丸かっこは「いま実行しろ」という命令です。付けて書くと、ページを開いた瞬間に showMessage が 1 回動いてしまい、その戻り値 (たいてい undefined) が addEventListener に渡ります。結果として、クリックしても何も起きないのに開いた瞬間だけ勝手に動く、という不思議な挙動になります。
その場に処理を書き下ろすなら、無名関数やアロー関数をそのまま置きます。
helloButton.addEventListener("click", () => {
helloMessage.textContent = "こんにちは。山田 太郎です。";
});名前を付けた関数を渡すか、その場に書くか。どちらでも動きます。同じ処理を複数の要素に付けるなら名前を付けて使い回し、その場限りなら無名関数にする、という選び分けが多いです。名前を付けておくと、あとで
removeEventListenerで取り外せるという利点もあります。
onclick 属性ではなく addEventListener を使う
HTML の属性としてイベントを書く方法もあります。<button onclick="showMessage()"> のような書き方です。短くて手軽ですが、いまの現場ではほとんど使いません。違いをまとめると次のようになります。
| 見るところ | onclick 属性 | addEventListener |
|---|---|---|
| 書く場所 | HTML の中 | JavaScript の中 |
| 同じイベントに複数 | 後から書いたほうで上書きされる | いくつでも重ねられる |
| 取り外し | 属性を消すしかない | removeEventListener で外せる |
| 役割の分かれ方 | 構造と動きが混ざる | 構造と動きが分かれる |
第8章でやったように、HTML を JavaScript から描き出すようになると、そもそも属性を書く場所がありません。最初から addEventListener で書く癖を付けておくのが結局いちばん楽です。
今回書くこと
自己紹介のところに、押すとあいさつが出るボタンを足します。HTML に id="hello-button" のボタンと、id="hello-message" の空の段落を置きます。あとは JavaScript でこの 2 つを取ってきて、ボタンの click にあいさつを表示する処理を結び付けます。
ボタンには type="button" を付けてください。フォームの外なので今回は影響しませんが、button 要素の既定は送信ボタンです。癖として付けておくと、あとでフォームの中に置いたときに困りません。
よくある間違い
丸かっこを付けて渡してしまう
// 開いた瞬間に 1 回動いて、そこで終わり
helloButton.addEventListener("click", showMessage());丸かっこを外して showMessage と書きます。渡すのは関数そのものです。
要素を取る前で綴りを間違えている
const helloButton = document.querySelector("#hello-buton");
helloButton.addEventListener("click", showMessage);id の綴りが 1 文字違うと helloButton は null になり、Cannot read properties of null で止まります。エラーが指す行番号は addEventListener の行ですが、本当の原因は 1 行上にあります。
イベント名に on を付ける
helloButton.addEventListener("onclick", showMessage);addEventListener に渡す名前に on は付けません。"click" です。エラーは出ず、ただ何も起きないので気付きにくい間違いです。
課題
- HTML の
#aboutの中にid="hello-button"type="button"class="submit-button"のボタンを足し、文字は「あいさつする」にする - そのすぐ下に
id="hello-message"の空のpを足す - JavaScript で
#hello-buttonにclickを登録し、#hello-messageのtextContentに「こんにちは。山田 太郎です。」を入れる - 第 2 引数には関数そのものを渡す。丸かっこを付けて呼ばない