JavaScript | ゼロからはじめるプログラミング、30日で基礎を学ぶJavaScript:Webページを操作できるようになる - Day17:イベント処理

JavaScript JavaScript
スポンサーリンク

Day17 後半のゴール

後半では、click イベントを
「ただのきっかけ」から「アプリの動きを司る中心」まで引き上げます。

前半で学んだ addEventListener(“click”, …) を、
DOM 操作(textContent / createElement / appendChild)と組み合わせて、
「クリックで画面が変わる」パターンを自分で設計できるようになることがゴールです。

Day17 後半でつかみたい感覚

クリックは“状態を変えるスイッチ”であり、その結果として画面が変わる

「状態(変数)」「イベント(click)」「DOM操作」をセットで考える

ここが腹に落ちると、
「ボタンを置いたら、とりあえず何か面白いことができる」という感覚になります。


クリックで状態を切り替える復習と深掘り

押すたびに ON / OFF を切り替える

まずはシンプルな「ON / OFF 切り替えボタン」を作ります。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Day17 イベント処理 後半</title>
  </head>
  <body>
    <h1 id="status">OFF</h1>
    <button id="toggleButton">切り替え</button>

    <script>
      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";
        }
      });
    </script>
  </body>
</html>

ここでの本質は、「クリックされた瞬間に画面を変える」のではなく、
「クリックされた瞬間に状態(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 が担当」という役割分担がはっきりします。

状態を変える処理
状態から画面を作る処理

この二つを分けておくと、
後から仕様変更が入っても壊れにくいコードになります。


クリックと createElement / appendChild を組み合わせる

クリックで新しい要素を追加する

Day16 で学んだ createElement / appendChild と click イベントを組み合わせると、
「クリックするたびに要素が増える」動きを作れます。

例として、「ログを追加するボタン」を作ってみます。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Day17 イベント処理 後半</title>
  </head>
  <body>
    <h1>クリックログ</h1>
    <button id="logButton">ログを追加</button>
    <div id="logContainer"></div>

    <script>
      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);
      });
    </script>
  </body>
</html>

ここでは、click イベントが「新しい要素を作るトリガー」になっています。

クリック
→ count を増やす
→ createElement で p を作る
→ textContent にメッセージを入れる
→ appendChild で logContainer に追加

クリックが「状態の変化」と「DOM の変化」の両方を引き起こしている、という構造です。

セキュリティの視点:ユーザー入力を使うとき

もし、ユーザーが入力した文字列をログに含める場合も、
textContent を使っていれば安全側に倒せます。

const inputElement = document.getElementById("textInput");

logButtonElement.addEventListener("click", () => {
  const text = inputElement.value;

  const p = document.createElement("p");
  p.textContent = `入力: ${text}`;
  logContainerElement.appendChild(p);
});
JavaScript

textContent は、
<script>...</script> のような文字列も「ただの文字」として扱うため、
スクリプトが実行されることはありません。

click イベントと DOM 操作を組み合わせるときほど、
innerHTML を安易に使わない意識が重要になります。


複数のクリックイベントで役割を分ける

「追加」と「クリア」の二つのボタン

次は、二つのボタンを用意して、
片方は「追加」、もう片方は「クリア」という役割にしてみます。

<h1>メモログ</h1>
<input id="memoInput" type="text">
<button id="addButton">追加</button>
<button id="clearButton">クリア</button>
<div id="memoContainer"></div>

JavaScript はこう書けます。

const memoInputElement = document.getElementById("memoInput");
const addButtonElement = document.getElementById("addButton");
const clearButtonElement = document.getElementById("clearButton");
const memoContainerElement = document.getElementById("memoContainer");

addButtonElement.addEventListener("click", () => {
  const text = memoInputElement.value;

  if (text === "") {
    return;
  }

  const p = document.createElement("p");
  p.textContent = text;
  memoContainerElement.appendChild(p);

  memoInputElement.value = "";
});

clearButtonElement.addEventListener("click", () => {
  memoContainerElement.textContent = "";
});
JavaScript

ここでのポイントは、
「それぞれのボタンに、それぞれの click イベントを付けている」ことです。

追加ボタンの click
→ 新しい p を作って appendChild

クリアボタンの click
→ memoContainer の中身を空文字にして、子要素を全部消す

click イベントは「1つのボタンに1つだけ」ではなく、
複数のボタンにそれぞれ別の処理を割り当てられる、という感覚を持っておくと良いです。


イベントオブジェクトに軽く触れておく

event 引数で「何が起きたか」の情報を受け取れる

click イベントのハンドラは、
実は「イベントオブジェクト」と呼ばれる情報を受け取ることができます。

button.addEventListener("click", (event) => {
  console.log(event);
});
JavaScript

この event には、
どの要素がクリックされたか
どの座標でクリックされたか
修飾キー(Ctrl / Shift など)が押されていたか

といった情報が入っています。

Day17 の段階では「そういうものがある」くらいで十分ですが、
「イベントハンドラの第一引数には event が来る」という形だけ覚えておくと、
後でキーボードイベントやマウスイベントを扱うときにスムーズです。


ありがちなつまずきと対処

addEventListener の書き方ミス

よくあるミスの一つが、
関数を「呼び出して」渡してしまうパターンです。

// よくある間違い
button.addEventListener("click", handleClick());
JavaScript

これだと、addEventListener を呼んだ瞬間に 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 後半のミニサンプル:全部入り

クリックで追加・カウント・クリアを行う小さなアプリ

最後に、Day15〜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;

        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 までの要素がほぼ全部入っています。

click イベント
状態管理(count)
textContent の更新
createElement / appendChild
入力値のチェック
複数ボタンへのイベント登録

このレベルのコードが「自分で考えて書ける」ようになると、
もう立派に「小さな Web アプリを作れる人」です。


Day17 後半のまとめ

click イベントは、
「ユーザーの操作をきっかけに、状態と画面を変えるスイッチ」です。

後半では、

クリックで状態を切り替える(ON / OFF)
状態と表示を関数で分ける
クリックで新しい要素を追加する
複数のボタンにそれぞれ click イベントを付ける
イベントオブジェクトの存在を知る
関数を“渡す”ことと“呼び出す”ことの違いを意識する

ところまで踏み込みました。

ここまで来たあなたは、
「クリックされたら何をしたいか」を自分で設計し、
コードに落とし込める段階にいます。
この感覚は、この先のキーボードイベントやフォーム送信、
さらには非同期処理とも自然につながっていきます。

タイトルとURLをコピーしました