Day17 後半のゴール
後半では、click イベントを「ただのきっかけ」から一歩進めて、
状態を変える、要素を増やす・消す、見た目を切り替える――
そういう“ミニアプリの心臓”として扱えるようになることを目指します。
ここで大事なのは、クリックをこう捉えることです。
「クリックされた瞬間に、状態を変える」
「変わった状態を、DOM(画面)に反映する」
この二段構えの感覚を、体に染み込ませていきます。
クリックで状態を切り替える
ON / OFF トグルの基本パターン
まずは「押すたびに ON / OFF が切り替わる」ボタンからいきます。
<h1 id="status">OFF</h1>
<button id="toggleButton">切り替え</button>
const statusElement = document.getElementById("status");
const toggleButtonElement = document.getElementById("toggleButton");
let isOn = false;
toggleButtonElement.addEventListener("click", () => {
isOn = !isOn;
if (isOn) {
statusElement.textContent = "ON";
} else {
statusElement.textContent = "OFF";
}
});
JavaScriptここで本当に理解してほしいのは、「クリックされた瞬間に何が起きているか」です。
まず isOn = !isOn で状態を反転させる。
そのあと、その状態に応じて textContent を書き換える。
つまり、クリックは「状態を変えるスイッチ」であり、
画面の変化は「状態の結果」として起きている、という構造になっています。
状態と表示を関数で分ける
もう一歩整理して、表示更新を関数に切り出してみます。
let isOn = false;
function updateStatus() {
if (isOn) {
statusElement.textContent = "ON";
} else {
statusElement.textContent = "OFF";
}
}
toggleButtonElement.addEventListener("click", () => {
isOn = !isOn;
updateStatus();
});
updateStatus();
JavaScriptこうすると、役割がはっきり分かれます。
クリックイベントは「状態を変えるだけ」。
画面の更新は updateStatus が担当。
この分離は、アプリが大きくなったときに効いてきます。
「状態」と「表示」を頭の中で分けて考えられる人は、バグが少ないです。
クリックと DOM 生成を組み合わせる
クリックでログを増やすミニアプリ
次は、クリックするたびにログを追加していく例です。
<h1>クリックログ</h1>
<button id="logButton">ログを追加</button>
<div id="logContainer"></div>
const logButtonElement = document.getElementById("logButton");
const logContainerElement = document.getElementById("logContainer");
let count = 0;
logButtonElement.addEventListener("click", () => {
count += 1;
const p = document.createElement("p");
p.textContent = `ボタンが ${count} 回クリックされました。`;
logContainerElement.appendChild(p);
});
JavaScriptここでは、クリックが二つのことを引き起こしています。
count を増やす(状態の更新)。
新しい p 要素を作って appendChild する(DOM の更新)。
Day16 で学んだ createElement / appendChild が、
click イベントと組み合わさることで「動く UI」になっているのが分かると思います。
入力とクリックを組み合わせる
入力欄の内容を追加する
次は、ユーザーが入力したテキストを、クリックで追加していくパターンです。
<input id="textInput" type="text" placeholder="メモを入力">
<button id="addButton">追加</button>
<div id="memoContainer"></div>
const textInputElement = document.getElementById("textInput");
const addButtonElement = document.getElementById("addButton");
const memoContainerElement = document.getElementById("memoContainer");
addButtonElement.addEventListener("click", () => {
const text = textInputElement.value;
if (text === "") {
return;
}
const p = document.createElement("p");
p.textContent = text;
memoContainerElement.appendChild(p);
textInputElement.value = "";
});
JavaScriptここでセキュリティ的に重要なのは、textContent を使っていることです。
textContent は「文字として扱う」ので、
ユーザーが <script>...</script> のような文字列を入れても、
それはただの文字列として表示され、実行されません。
click イベントとユーザー入力を組み合わせるときほど、
innerHTML を安易に使わない、という意識が大事です。
複数のボタンで役割を分ける
追加ボタンとクリアボタン
もう少しアプリっぽくしてみましょう。
「追加」と「クリア」の二つのボタンを用意します。
<input id="textInput" type="text" placeholder="メモを入力">
<button id="addButton">追加</button>
<button id="clearButton">クリア</button>
<div id="memoContainer"></div>
const textInputElement = document.getElementById("textInput");
const addButtonElement = document.getElementById("addButton");
const clearButtonElement = document.getElementById("clearButton");
const memoContainerElement = document.getElementById("memoContainer");
addButtonElement.addEventListener("click", () => {
const text = textInputElement.value;
if (text === "") {
return;
}
const p = document.createElement("p");
p.textContent = text;
memoContainerElement.appendChild(p);
textInputElement.value = "";
});
clearButtonElement.addEventListener("click", () => {
memoContainerElement.textContent = "";
});
JavaScriptここで意識してほしいのは、「ボタンごとに責任が違う」ということです。
追加ボタンの click は「新しい要素を作って追加する」。
クリアボタンの click は「中身を全部消す」。
click イベントは「どの要素に付けるか」で意味が変わる。
この感覚が入ると、UI を設計するのが楽しくなります。
イベントオブジェクトに軽く触れておく
event から「何が起きたか」の情報を取れる
click イベントのハンドラは、実は引数を受け取れます。
button.addEventListener("click", (event) => {
console.log(event);
});
JavaScriptこの event の中には、
どの要素がクリックされたか(event.target)
どの座標でクリックされたか
どんなキーが押されていたか(Ctrl / Shift など)
といった情報が入っています。
Day17 の段階では「そういう情報が取れるんだな」くらいで十分です。
ただ、「イベントハンドラの第一引数には event が来る」という形だけ覚えておくと、
後でキーボードイベントやマウスイベントを扱うときにスムーズです。
ありがちなつまずきと、その直し方
関数を“渡す”のではなく“呼び出してしまう”ミス
よくあるのが、このパターンです。
button.addEventListener("click", handleClick());
JavaScriptこれは「今すぐ handleClick を実行して、その戻り値をイベントハンドラとして渡す」という意味になってしまいます。
たいてい戻り値は undefined なので、クリックしても何も起きません。
正しくはこうです。
button.addEventListener("click", handleClick);
JavaScriptあるいは無名関数で包むならこう。
button.addEventListener("click", () => {
handleClick();
});
JavaScript「関数そのものを渡す」と「関数を呼び出す」の違いを、
ここでしっかり区別できるようになっておくと、イベント周りのバグが一気に減ります。
要素がまだ存在しないタイミングでイベントを付けようとする
script を head の中に書いて、
まだ body の要素が読み込まれていないタイミングで getElementById すると、null になります。
Day17 の段階では、素直に script を body の一番下に置くのがおすすめです。
<body>
<!-- 要素たち -->
<script>
// ここなら、上の要素が読み込まれた後に実行される
</script>
</body>
それでも不安なら、null チェックを入れておくのも良い習慣です。
Day17 後半のミニ総合サンプル
クリックで追加・カウント・クリアを行う小さなアプリ
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Day17 イベント処理 後半</title>
</head>
<body>
<h1 id="title">クリック練習アプリ</h1>
<p>
メモ:<input id="memoInput" type="text">
<button id="addButton">追加</button>
<button id="clearButton">クリア</button>
</p>
<p id="countText">追加回数: 0</p>
<div id="memoContainer"></div>
<script>
const titleElement = document.getElementById("title");
const memoInputElement = document.getElementById("memoInput");
const addButtonElement = document.getElementById("addButton");
const clearButtonElement = document.getElementById("clearButton");
const countTextElement = document.getElementById("countText");
const memoContainerElement = document.getElementById("memoContainer");
let count = 0;
addButtonElement.addEventListener("click", () => {
const text = memoInputElement.value.trim();
if (text === "") {
titleElement.textContent = "メモを入力してください。";
return;
}
const p = document.createElement("p");
p.textContent = text;
memoContainerElement.appendChild(p);
count += 1;
countTextElement.textContent = `追加回数: ${count}`;
titleElement.textContent = "メモを追加しました。";
memoInputElement.value = "";
});
clearButtonElement.addEventListener("click", () => {
memoContainerElement.textContent = "";
count = 0;
countTextElement.textContent = "追加回数: 0";
titleElement.textContent = "メモをクリアしました。";
});
</script>
</body>
</html>
この小さなアプリの中に、Day17 のエッセンスが全部入っています。
クリックで状態を変える。
状態を textContent に反映する。
クリックで要素を増やす。
別のクリックで要素を消す。
ここまで自分で書けるようになったら、
「クリックで何かを起こす」ことに関しては、もう十分に戦えるレベルです。
Day17 後半のまとめ
click イベントは、
「ユーザーの操作をきっかけに、状態と DOM を変えるスイッチ」です。
後半では、
ON / OFF のトグルで「状態と表示」の関係を意識すること。
クリックと createElement / appendChild を組み合わせて、要素を増やすこと。
入力+クリックで、ユーザーのデータを画面に反映すること。
複数ボタンにそれぞれ役割を持たせること。
関数を“渡す”ことと“呼び出す”ことの違いをはっきりさせること。
ここまで踏み込んでいます。
この感覚が入っていると、この先のキーボードイベント、フォーム送信、非同期処理も、
「きっかけ → 状態 → DOM」という同じパターンで理解できるようになります。
いい土台、もうできてるよ。
