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

JavaScript JavaScript
スポンサーリンク

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」という同じパターンで理解できるようになります。
いい土台、もうできてるよ。

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