基礎から学ぶJavaScript入門 90日コース | Webページを操作するDOM - Day 39:イベントオブジェクト

JavaScript 90日で身につけるJavaScript
スポンサーリンク
スポンサーリンク
  1. Day 39:イベントオブジェクト(前半)
  2. イベントオブジェクト event とは何か
    1. イベントが起きたときに渡される“情報のかたまり”
    2. イベントハンドラの引数として渡される
  3. event.target とは何か
    1. 「実際に操作された要素」を指すプロパティ
    2. 具体的なイメージ
  4. 実践:クリックされた要素を判定する
    1. 目標イメージ
  5. Step 1:HTMLを用意する
  6. Step 2:イベントオブジェクトを受け取る
  7. Step 3:event.target で「誰がクリックされたか」を知る
  8. Step 4:クリックされた要素がボタンかどうかを判定する
  9. Step 5:data属性から“ボタンの意味”を取り出す
  10. Step 6:クリックされたボタンに応じてメッセージを表示する
  11. 完成コード(コメント付き)
  12. event.target を使うメリット
    1. 1. コードがシンプルになる
    2. 2. 動的に追加された要素にも対応しやすい
  13. セキュリティ・安全性の観点からの補足
  14. Day 39 前半 練習用テンプレート
  15. Day 39 前半のまとめ
  16. Day 39:イベントオブジェクト(後半)
  17. イベント委譲という考え方
    1. たくさんの要素にイベントを付けると何が起きるか
    2. 親要素に1つだけイベントを付ける「イベント委譲」
  18. 実践:イベント委譲でクリックされた要素を判定する
    1. HTML:カード一覧を用意する
    2. JavaScript:親要素にだけイベントを付ける
  19. ネストされた要素の中で event.target がどこを指すか
    1. カードのどこをクリックしても「カード」として扱いたい
    2. event.target は「一番内側の要素」を指す
  20. 実践:closest() で「一番近い .card を探す」
    1. closest() とは何か
    2. closest() を使って「クリックされたカード」を特定する
  21. カードの情報を取り出してメッセージに表示する
    1. data-id からカードIDを取得する
    2. カードタイトルを取得する
    3. メッセージを更新する
  22. 完成コード(イベント委譲+closest+event.target)
  23. 条件付きクリック判定:特定のボタンだけ反応させる
    1. カードの中に「詳細ボタン」と「削除ボタン」がある場合
    2. className でクリックされた要素の種類を判定する
  24. セキュリティ・安全性の観点からの補足
  25. Day 39 後半 練習用テンプレート
  26. Day 39 後半のまとめ

Day 39:イベントオブジェクト(前半)

「event と event.target で“誰がクリックされたか”を正しく理解する」

Day 39前半では、JavaScriptのイベント処理の中でもとても重要な イベントオブジェクト を扱います。 これまで addEventListener('click', ...) のようにイベントを使ってきましたが、 今日は一歩踏み込んで 「eventとは何か」「event.targetとは何か」 を理解していきます。

実践テーマは 「クリックされた要素を判定」 です。 複数の要素がある中で、「どの要素がクリックされたのか」をコードで判定できるようになることを目指します。

イベントオブジェクト event とは何か

イベントが起きたときに渡される“情報のかたまり”

addEventListener でイベント処理を書くとき、 次のような形をよく見かけると思います。

element.addEventListener('click', function (event) {
  // ここで event を使う
});
JavaScript

この eventイベントオブジェクト です。

イベントオブジェクトは、

「クリックされた」「キーが押された」「フォームが送信された」などの “イベントが起きたときの情報”をまとめて持っているオブジェクト

だとイメージすると分かりやすいです。

例えば、クリックイベントなら、

  • どの要素がクリックされたか
  • どの座標でクリックされたか
  • どのボタン(左クリック・右クリックなど)だったか

といった情報が event の中に入っています。

イベントハンドラの引数として渡される

イベントオブジェクトは、 イベントハンドラ(イベントが起きたときに呼ばれる関数)の 引数 として渡されます。

element.addEventListener('click', function (event) {
  console.log(event); // イベントオブジェクトの中身を確認できます
});
JavaScript

ここで event という名前は慣例的なものなので、 eev など、別の名前にしても構いません。

element.addEventListener('click', function (e) {
  console.log(e);
});
JavaScript

ただし、初心者のうちは event という名前で統一しておく と、 「これはイベントオブジェクトだな」とすぐに分かるのでおすすめです。

event.target とは何か

「実際に操作された要素」を指すプロパティ

event の中でも、特に重要なのが event.target です。

event.target は、

「そのイベントを引き起こした“実際の要素”」

を指すプロパティです。

クリックイベントの場合、

  • クリックされた要素そのもの
  • つまり「どのタグがクリックされたか」を表す

という意味になります。

具体的なイメージ

例えば、次のようなHTMLがあるとします。

<button id="btn1">ボタン1</button>
<button id="btn2">ボタン2</button>
<button id="btn3">ボタン3</button>

これらをまとめてクリック判定したいとき、 それぞれにイベントを付ける代わりに、 親要素にイベントを付けて event.target で「どれがクリックされたか」を判定することができます。

document.addEventListener('click', function (event) {
  console.log('クリックされた要素:', event.target);
});
JavaScript

このとき、

  • ボタン1をクリック → event.target<button id="btn1">...
  • ボタン2をクリック → event.target<button id="btn2">...

というように、 クリックされた要素そのものevent.target に入ります。

実践:クリックされた要素を判定する

目標イメージ

  • ページ上に複数のボタンやリンクがある。
  • どれがクリックされたかを event.target で判定する。
  • クリックされた要素に応じてメッセージを変える。

これを、ステップバイステップで作っていきます。

Step 1:HTMLを用意する

まずは、複数のボタンを用意します。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Day 39 前半:イベントオブジェクトとクリック判定</title>
</head>
<body>
  <h1>クリックされた要素を判定する</h1>

  <section id="buttonArea">
    <button data-name="apple">りんごボタン</button>
    <button data-name="orange">みかんボタン</button>
    <button data-name="banana">バナナボタン</button>
  </section>

  <p id="message">どのボタンがクリックされたか表示します。</p>

  <script>
    // ここにJavaScriptを書いていきます
  </script>
</body>
</html>

ポイントは、

  • sectionid="buttonArea" を付けて、 その中のボタンをまとめて扱えるようにしていること。
  • 各ボタンに data-name 属性を付けて、 「りんご」「みかん」「バナナ」といった識別情報を持たせていること。

data-* 属性は、 「HTML要素に任意のデータを持たせるための仕組み」 で、 JavaScriptから簡単に参照できます。

Step 2:イベントオブジェクトを受け取る

次に、buttonArea にクリックイベントを付けます。

// ▼ ボタンをまとめているエリアを取得します
const buttonAreaElement = document.getElementById('buttonArea');

// ▼ メッセージ表示用の<p>要素を取得します
const messageElement = document.getElementById('message');

// ▼ buttonArea内でクリックが起きたときの処理
buttonAreaElement.addEventListener('click', function (event) {
  console.log('イベントオブジェクト:', event); // 中身を確認してみましょう
});
JavaScript

ここで、イベントハンドラの引数 event が、 クリックイベントの情報を持つイベントオブジェクト です。

Step 3:event.target で「誰がクリックされたか」を知る

次に、event.target を使って、 「どの要素がクリックされたか」を判定します。

buttonAreaElement.addEventListener('click', function (event) {
  // ▼ クリックされた“実際の要素”を取得します
  const clickedElement = event.target;

  console.log('クリックされた要素:', clickedElement);
});
JavaScript

ここで clickedElement には、

  • ボタンがクリックされた場合 → その <button> 要素
  • もしボタンの中に別の要素があれば → その内側の要素

が入ります。

Step 4:クリックされた要素がボタンかどうかを判定する

buttonArea の中には、 将来的にボタン以外の要素が入る可能性もあります。

そこで、

「クリックされた要素が <button> かどうか」

を判定してから処理するようにします。

buttonAreaElement.addEventListener('click', function (event) {
  const clickedElement = event.target;

  // ▼ クリックされた要素が<button>でなければ何もしません
  if (clickedElement.tagName !== 'BUTTON') {
    return;
  }

  console.log('ボタンがクリックされました:', clickedElement);
});
JavaScript

tagName は、 要素のタグ名(BUTTON, DIV, SPAN など)を大文字で返すプロパティです。

Step 5:data属性から“ボタンの意味”を取り出す

各ボタンには、次のように data-name 属性を付けました。

<button data-name="apple">りんごボタン</button>
<button data-name="orange">みかんボタン</button>
<button data-name="banana">バナナボタン</button>

この data-name は、 JavaScriptから次のように取得できます。

const fruitName = clickedElement.dataset.name;
JavaScript

dataset は、

data- から始まる属性をまとめて扱うためのオブジェクト

で、

  • data-namedataset.name
  • data-user-iddataset.userId

というように変換されます。

Step 6:クリックされたボタンに応じてメッセージを表示する

ここまでを組み合わせて、 「どのボタンがクリックされたか」をメッセージに表示します。

buttonAreaElement.addEventListener('click', function (event) {
  const clickedElement = event.target;

  // ▼ ボタン以外がクリックされた場合は何もしません
  if (clickedElement.tagName !== 'BUTTON') {
    return;
  }

  // ▼ data-name 属性から“ボタンの意味”を取り出します
  const fruitName = clickedElement.dataset.name;

  // ▼ メッセージを更新します
  messageElement.textContent = `「${fruitName}」ボタンがクリックされました。`;
});
JavaScript

例えば、

  • りんごボタン → 「appleボタンがクリックされました。」
  • みかんボタン → 「orangeボタンがクリックされました。」

というように表示されます。

完成コード(コメント付き)

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Day 39 前半:イベントオブジェクトとクリック判定</title>
</head>
<body>
  <h1>クリックされた要素を判定する</h1>

  <!-- ▼ ボタンをまとめているエリア -->
  <section id="buttonArea">
    <!-- data-name 属性でボタンの意味を持たせています -->
    <button data-name="apple">りんごボタン</button>
    <button data-name="orange">みかんボタン</button>
    <button data-name="banana">バナナボタン</button>
  </section>

  <!-- ▼ メッセージ表示エリア -->
  <p id="message">どのボタンがクリックされたか表示します。</p>

  <script>
    // ▼ ボタンエリアとメッセージ要素を取得します
    const buttonAreaElement = document.getElementById('buttonArea');
    const messageElement = document.getElementById('message');

    // ▼ buttonArea内でクリックが起きたときの処理
    buttonAreaElement.addEventListener('click', function (event) {
      // event は「クリックイベントの情報が入ったオブジェクト」です
      console.log('イベントオブジェクト:', event);

      // ▼ 実際にクリックされた要素を取得します
      const clickedElement = event.target;

      console.log('クリックされた要素:', clickedElement);

      // ▼ クリックされた要素が<button>でなければ何もしません
      if (clickedElement.tagName !== 'BUTTON') {
        return;
      }

      // ▼ data-name 属性からボタンの意味を取り出します
      const fruitName = clickedElement.dataset.name;

      // ▼ メッセージを更新します
      messageElement.textContent = `「${fruitName}」ボタンがクリックされました。`;
    });
  </script>
</body>
</html>

event.target を使うメリット

1. コードがシンプルになる

それぞれのボタンに個別にイベントを付けることもできますが、 event.target を使うと、

  • 親要素に1つだけイベントを付ける
  • クリックされた要素を event.target で判定する

という書き方ができ、コードがシンプルになります。

これは イベント委譲(イベントデリゲーション) と呼ばれるテクニックで、 要素が増えてもイベント処理を増やさずに済むため、 大規模なUIでもよく使われます。

2. 動的に追加された要素にも対応しやすい

前のDayで学んだように、 createElement()appendChild() で要素を追加することができます。

event.target を使った書き方なら、

  • 後から追加されたボタンも
  • 同じ親要素の中にあれば

同じイベント処理で扱うことができます。

これは、

「最初からある要素だけでなく、後から増える要素もまとめて扱いたい」

という場面で非常に役立ちます。

セキュリティ・安全性の観点からの補足

イベントオブジェクト自体は、 ブラウザが提供する安全な情報のかたまりです。

ただし、イベント処理の中で、

  • ユーザー入力を扱う
  • DOMを書き換える

といった操作を行う場合は、 次の点に注意する必要があります。

  • ユーザー入力を画面に表示するときは、textContent を使う
    • innerHTML を使うと、入力された文字列がHTMLとして解釈されてしまい、 <script> などが実行される危険があります。
  • event.target から取得した要素に対して、 不必要に innerHTML を書き換えない。

今回のコードでは、 メッセージ表示に textContent を使っているため、 安全にテキストを扱うことができています。

Day 39 前半 練習用テンプレート

最後に、今日の内容をまとめて練習できるテンプレートを紹介します。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Day 39 前半:イベントオブジェクト 練習テンプレート</title>
</head>
<body>
  <h1>イベントオブジェクトと event.target 練習</h1>

  <section id="buttonArea">
    <button data-name="apple">りんご</button>
    <button data-name="orange">みかん</button>
    <button data-name="banana">バナナ</button>
  </section>

  <p id="message">クリックしたボタンの情報がここに表示されます。</p>

  <script>
    console.log('--- イベントオブジェクト 練習開始 ---');

    const buttonAreaElement = document.getElementById('buttonArea');
    const messageElement = document.getElementById('message');

    buttonAreaElement.addEventListener('click', function (event) {
      console.log('event:', event);

      const clickedElement = event.target;
      console.log('event.target:', clickedElement);

      if (clickedElement.tagName !== 'BUTTON') {
        console.log('ボタン以外がクリックされました。処理をスキップします。');
        return;
      }

      const fruitName = clickedElement.dataset.name;

      messageElement.textContent = `「${fruitName}」ボタンがクリックされました。`;
      console.log('クリック判定結果:', fruitName);
    });

    console.log('--- イベントオブジェクト 練習テンプレートの準備が完了しました ---');
  </script>
</body>
</html>

Day 39 前半のまとめ

Day 39前半では、

  • イベントオブジェクト event が、 「イベントが起きたときの情報のかたまり」であること。
  • event.target が、 「実際に操作された要素(クリックされた要素)」を指すプロパティであること。
  • 親要素に1つだけイベントを付けて、 event.target で「どのボタンがクリックされたか」を判定するテクニックを学んだこと。
  • ユーザー入力やDOM操作を行うときに、 textContent を使って安全性を意識すること。

を整理しました。

この「event と event.target を理解する」ステップは、 次のDayで学ぶ イベント伝播(バブリング・キャプチャ) や、 より高度なイベント設計の土台になります。

今日のコードを何度か書き直しながら、

「イベントが起きたとき、ブラウザはどんな情報を渡してくれているのか」

を意識して練習していくことで、 イベント処理を“感覚ではなく、構造として理解する”力が育っていきます。


Day 39:イベントオブジェクト(後半)

「event と event.target を“使いこなしている側”になるクリック判定の実践編」

Day 39後半では、前半で学んだ event event.target を、 実際の現場でよく使われる形にまで育てていきます。

テーマは同じく 「クリックされた要素を判定」 ですが、 後半では次のようなポイントを意識して深掘りしていきます。

  • 親要素に1つだけイベントを付ける「イベント委譲」
  • ネストされた要素の中で、event.target がどこを指すか
  • クラス名や data 属性を使った「条件付きクリック判定」

「なんとなく動く」から一歩進んで、 「意図を持って設計されたイベント処理」 を書けるようになることを目指します。

イベント委譲という考え方

たくさんの要素にイベントを付けると何が起きるか

例えば、10個のボタンがあるとします。

<button>ボタン1</button>
<button>ボタン2</button>
...
<button>ボタン10</button>

これらすべてに対して、

button1.addEventListener('click', ...);
button2.addEventListener('click', ...);
// ...
button10.addEventListener('click', ...);
JavaScript

とイベントを付けていくと、

  • コード量が増える
  • 後からボタンが増えたときに、またイベントを追加しないといけない
  • 管理が大変になる

という問題が出てきます。

親要素に1つだけイベントを付ける「イベント委譲」

そこで登場するのが イベント委譲(Event Delegation) です。

考え方はシンプルで、

「たくさんの子要素にイベントを付ける代わりに、 親要素に1つだけイベントを付けて、 event.target で“どの子がクリックされたか”を判定する」

というものです。

これにより、

  • イベントリスナーの数が減る
  • 後から追加された子要素にも自動的に対応できる
  • コードがシンプルになる

というメリットがあります。

実践:イベント委譲でクリックされた要素を判定する

HTML:カード一覧を用意する

ボタンではなく「カード」を例にしてみます。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Day 39 後半:イベント委譲でクリック判定</title>
  <style>
    .card-list {
      display: flex;
      gap: 16px;
    }
    .card {
      border: 1px solid #ccc;
      padding: 8px;
      width: 150px;
      cursor: pointer;
    }
    .card-title {
      font-weight: bold;
    }
    .card-body {
      font-size: 14px;
    }
  </style>
</head>
<body>
  <h1>カード一覧(クリックされたカードを判定)</h1>

  <section id="cardList" class="card-list">
    <article class="card" data-id="1">
      <h2 class="card-title">カード1</h2>
      <p class="card-body">これはカード1の説明です。</p>
    </article>

    <article class="card" data-id="2">
      <h2 class="card-title">カード2</h2>
      <p class="card-body">これはカード2の説明です。</p>
    </article>

    <article class="card" data-id="3">
      <h2 class="card-title">カード3</h2>
      <p class="card-body">これはカード3の説明です。</p>
    </article>
  </section>

  <p id="message">クリックされたカードの情報をここに表示します。</p>

  <script>
    // ここにJavaScriptを書いていきます
  </script>
</body>
</html>

ポイントは、

  • 親要素として id="cardList" を持つ <section> があること
  • 各カードが .card クラスを持つ <article> であること
  • 各カードに data-id 属性でIDを持たせていること

です。

JavaScript:親要素にだけイベントを付ける

// ▼ 親要素(カード一覧)を取得します
const cardListElement = document.getElementById('cardList');

// ▼ メッセージ表示用の<p>要素を取得します
const messageElement = document.getElementById('message');

// ▼ cardList内でクリックが起きたときの処理
cardListElement.addEventListener('click', function (event) {
  // event は「クリックイベントの情報が入ったオブジェクト」です
  console.log('event:', event);

  // ▼ 実際にクリックされた要素を取得します
  const clickedElement = event.target;
  console.log('event.target:', clickedElement);
});
JavaScript

ここまでは前半と同じですが、 後半ではここから 「カードを特定する」 ところまで踏み込みます。

ネストされた要素の中で event.target がどこを指すか

カードのどこをクリックしても「カード」として扱いたい

カードの中には、

  • タイトル(<h2>
  • 説明文(<p>

など、複数の要素が入っています。

ユーザーがクリックする場所は、

  • タイトル部分
  • 説明文部分
  • カードの余白部分

など、バラバラです。

しかし、アプリとしては、

「カードのどこをクリックしても、そのカードがクリックされた」

とみなしたいことが多いです。

event.target は「一番内側の要素」を指す

クリックイベントでは、

  • タイトルをクリック → event.target<h2 class="card-title">...
  • 説明文をクリック → event.target<p class="card-body">...
  • カードの余白をクリック → event.target<article class="card">...

というように、 「一番内側の要素」event.target になります。

そのため、

「クリックされたカード(<article class="card">)を知りたい」

場合は、 event.target から親要素をたどっていく必要があります。

実践:closest() で「一番近い .card を探す」

closest() とは何か

closest() は、DOM要素のメソッドで、

「自分自身から親方向にたどっていき、 指定したセレクタにマッチする一番近い要素を返す」

というものです。

例えば、

const cardElement = clickedElement.closest('.card');
JavaScript

とすると、

  • clickedElement.card 自身なら → その要素
  • clickedElement.card の中の <h2><p> なら → 親の .card 要素
  • .card の外側なら → null

が返ってきます。

closest() を使って「クリックされたカード」を特定する

cardListElement.addEventListener('click', function (event) {
  const clickedElement = event.target;

  // ▼ クリックされた要素から、一番近い .card 要素を探します
  const cardElement = clickedElement.closest('.card');

  // ▼ .card の外側がクリックされた場合は何もしません
  if (!cardElement) {
    return;
  }

  console.log('クリックされたカード要素:', cardElement);
});
JavaScript

これで、

  • タイトルをクリックしても
  • 説明文をクリックしても
  • カードの余白をクリックしても

常に「そのカードの <article class="card">」を取得できます。

カードの情報を取り出してメッセージに表示する

data-id からカードIDを取得する

各カードには data-id 属性があります。

<article class="card" data-id="1">...</article>

これは、JavaScriptから次のように取得できます。

const cardId = cardElement.dataset.id;
JavaScript

カードタイトルを取得する

カードのタイトルは <h2 class="card-title"> です。

const titleElement = cardElement.querySelector('.card-title');
const titleText = titleElement.textContent;
JavaScript

querySelector() は、

「その要素の中から、指定したCSSセレクタにマッチする最初の要素を返す」

メソッドです。

メッセージを更新する

これらを組み合わせて、 「どのカードがクリックされたか」をメッセージに表示します。

cardListElement.addEventListener('click', function (event) {
  const clickedElement = event.target;

  const cardElement = clickedElement.closest('.card');

  if (!cardElement) {
    return;
  }

  const cardId = cardElement.dataset.id;
  const titleElement = cardElement.querySelector('.card-title');
  const titleText = titleElement.textContent;

  messageElement.textContent = `カードID: ${cardId}${titleText})がクリックされました。`;
});
JavaScript

完成コード(イベント委譲+closest+event.target)

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Day 39 後半:イベント委譲でクリックされた要素を判定</title>
  <style>
    .card-list {
      display: flex;
      gap: 16px;
    }
    .card {
      border: 1px solid #ccc;
      padding: 8px;
      width: 150px;
      cursor: pointer;
    }
    .card-title {
      font-weight: bold;
      margin-bottom: 4px;
    }
    .card-body {
      font-size: 14px;
    }
  </style>
</head>
<body>
  <h1>カード一覧(クリックされたカードを判定)</h1>

  <section id="cardList" class="card-list">
    <article class="card" data-id="1">
      <h2 class="card-title">カード1</h2>
      <p class="card-body">これはカード1の説明です。</p>
    </article>

    <article class="card" data-id="2">
      <h2 class="card-title">カード2</h2>
      <p class="card-body">これはカード2の説明です。</p>
    </article>

    <article class="card" data-id="3">
      <h2 class="card-title">カード3</h2>
      <p class="card-body">これはカード3の説明です。</p>
    </article>
  </section>

  <p id="message">クリックされたカードの情報をここに表示します。</p>

  <script>
    // ▼ 親要素(カード一覧)とメッセージ要素を取得します
    const cardListElement = document.getElementById('cardList');
    const messageElement = document.getElementById('message');

    // ▼ cardList内でクリックが起きたときの処理
    cardListElement.addEventListener('click', function (event) {
      // event は「クリックイベントの情報が入ったオブジェクト」です
      console.log('event:', event);

      // ▼ 実際にクリックされた一番内側の要素
      const clickedElement = event.target;
      console.log('event.target:', clickedElement);

      // ▼ クリックされた要素から、一番近い .card 要素を探します
      const cardElement = clickedElement.closest('.card');

      // ▼ .card の外側がクリックされた場合は何もしません
      if (!cardElement) {
        console.log('カード以外がクリックされました。処理をスキップします。');
        return;
      }

      // ▼ カードIDとタイトルを取得します
      const cardId = cardElement.dataset.id;
      const titleElement = cardElement.querySelector('.card-title');
      const titleText = titleElement.textContent;

      // ▼ メッセージを更新します
      messageElement.textContent = `カードID: ${cardId}(${titleText})がクリックされました。`;

      console.log('クリックされたカード:', { id: cardId, title: titleText });
    });
  </script>
</body>
</html>

条件付きクリック判定:特定のボタンだけ反応させる

カードの中に「詳細ボタン」と「削除ボタン」がある場合

もう少し現場寄りの例として、 カードの中に「詳細を見る」ボタンと「削除」ボタンがあるケースを考えてみます。

<article class="card" data-id="1">
  <h2 class="card-title">カード1</h2>
  <p class="card-body">これはカード1の説明です。</p>
  <button class="detail-button">詳細を見る</button>
  <button class="delete-button">削除</button>
</article>

このとき、

  • カードのどこをクリックしても「カードクリック」として扱いたい
  • ただし、「削除」ボタンは別の処理をしたい

というように、 クリックされた要素の種類によって処理を変えたい 場面が出てきます。

className でクリックされた要素の種類を判定する

cardListElement.addEventListener('click', function (event) {
  const clickedElement = event.target;

  // ▼ 削除ボタンがクリックされた場合
  if (clickedElement.classList.contains('delete-button')) {
    const cardElement = clickedElement.closest('.card');
    const cardId = cardElement.dataset.id;

    alert(`カードID: ${cardId} を削除します。(仮)`);
    return;
  }

  // ▼ 詳細ボタンがクリックされた場合
  if (clickedElement.classList.contains('detail-button')) {
    const cardElement = clickedElement.closest('.card');
    const cardId = cardElement.dataset.id;

    alert(`カードID: ${cardId} の詳細を表示します。(仮)`);
    return;
  }

  // ▼ それ以外(カード本体のクリック)は、カードクリックとして扱う
  const cardElement = clickedElement.closest('.card');

  if (!cardElement) {
    return;
  }

  const cardId = cardElement.dataset.id;
  const titleText = cardElement.querySelector('.card-title').textContent;

  messageElement.textContent = `カードID: ${cardId}${titleText})がクリックされました。`;
});
JavaScript

ここでは、

  • event.target からクリックされた要素を取得
  • classList.contains() でクラス名を判定
  • 要素の種類に応じて処理を分岐

という流れになっています。

セキュリティ・安全性の観点からの補足

イベントオブジェクトと event.target を使うと、 ユーザーの操作に応じて柔軟にDOMを操作できます。

ただし、その分だけ、

  • ユーザー入力を画面に表示するとき
  • DOMを書き換えるとき

には、次の点に注意する必要があります。

  • ユーザー入力を表示するときは、必ず textContent を使う
    • innerHTML を使うと、入力された文字列がHTMLとして解釈されてしまい、 <script> などが実行される危険があります。
  • event.target から取得した要素に対して、 不必要に innerHTML を書き換えない。

今回のコードでは、 カードタイトルやメッセージ表示に textContent を使っているため、 安全にテキストを扱うことができています。

Day 39 後半 練習用テンプレート

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Day 39 後半:イベントオブジェクト 総合練習テンプレート</title>
  <style>
    .card-list {
      display: flex;
      gap: 16px;
    }
    .card {
      border: 1px solid #ccc;
      padding: 8px;
      width: 180px;
      cursor: pointer;
    }
    .card-title {
      font-weight: bold;
      margin-bottom: 4px;
    }
    .card-body {
      font-size: 14px;
      margin-bottom: 8px;
    }
    .detail-button,
    .delete-button {
      margin-right: 4px;
    }
  </style>
</head>
<body>
  <h1>Day 39 後半:event と event.target 総合練習</h1>

  <section id="cardList" class="card-list">
    <article class="card" data-id="1">
      <h2 class="card-title">カード1</h2>
      <p class="card-body">カード1の説明テキストです。</p>
      <button class="detail-button">詳細を見る</button>
      <button class="delete-button">削除</button>
    </article>

    <article class="card" data-id="2">
      <h2 class="card-title">カード2</h2>
      <p class="card-body">カード2の説明テキストです。</p>
      <button class="detail-button">詳細を見る</button>
      <button class="delete-button">削除</button>
    </article>
  </section>

  <p id="message">ここにクリック結果が表示されます。</p>

  <script>
    console.log('--- Day 39 後半 総合練習開始 ---');

    const cardListElement = document.getElementById('cardList');
    const messageElement = document.getElementById('message');

    cardListElement.addEventListener('click', function (event) {
      const clickedElement = event.target;
      console.log('event.target:', clickedElement);

      // ▼ 削除ボタンがクリックされた場合
      if (clickedElement.classList.contains('delete-button')) {
        const cardElement = clickedElement.closest('.card');
        const cardId = cardElement.dataset.id;

        alert(`カードID: ${cardId} を削除します。(仮処理)`);
        console.log('削除ボタンがクリックされました:', cardId);
        return;
      }

      // ▼ 詳細ボタンがクリックされた場合
      if (clickedElement.classList.contains('detail-button')) {
        const cardElement = clickedElement.closest('.card');
        const cardId = cardElement.dataset.id;

        alert(`カードID: ${cardId} の詳細を表示します。(仮処理)`);
        console.log('詳細ボタンがクリックされました:', cardId);
        return;
      }

      // ▼ それ以外はカードクリックとして扱います
      const cardElement = clickedElement.closest('.card');

      if (!cardElement) {
        console.log('カード以外がクリックされました。処理をスキップします。');
        return;
      }

      const cardId = cardElement.dataset.id;
      const titleText = cardElement.querySelector('.card-title').textContent;

      messageElement.textContent = `カードID: ${cardId}(${titleText})がクリックされました。`;
      console.log('カードクリック:', { id: cardId, title: titleText });
    });

    console.log('--- Day 39 後半 総合練習テンプレートの準備が完了しました ---');
  </script>
</body>
</html>

Day 39 後半のまとめ

Day 39後半では、

  • eventevent.target を使って、 親要素に1つだけイベントを付ける「イベント委譲」を体験したこと。
  • ネストされた要素の中で、event.target が「一番内側の要素」を指すことを理解し、 closest() で「本当に扱いたい要素(カード)」を特定するテクニックを学んだこと。
  • クラス名や data 属性を使って、 「クリックされた要素の種類に応じて処理を分岐する」設計を練習したこと。
  • DOM操作とユーザー入力の扱いにおいて、 textContent を使って安全性を意識し続けたこと。

を整理しました。

この「event と event.target を意図を持って使いこなす」感覚は、 ボタン群、カード一覧、メニュー、タブUIなど、 多くのインタラクティブなUIでそのまま活かせます。

今日のコードを何度か書き直しながら、

「ユーザーがどこをクリックしたときに、どんな情報を取り出して、どんな処理をしたいのか」

を自分なりに言語化して設計していくことで、 イベント処理が“ただのテクニック”ではなく、 「ユーザー体験を形にする道具」として見えてくるようになります。

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