404 Not Found

404 Not Found


nginx

JavaScript イベント

イベントはユーザーまたはブラウザから送られる「シグナル」です。ユーザーがボタンをクリックしたり、キーを押したり、フォームを送信したり、ブラウザがページの読み込みを完了したり...这些都是イベントです。コードはこれらのイベントを「リスニング」し、適切なタイミングで応答します。ドアベルが鳴ってドアを開けるようなもので、ドアベルがイベント、ドアを開けるのが応答です。


イベントバインドの方法

JavaScript にはイベントハンドラを要素にバインドする3つの方法があります。

1. HTML 属性(非推奨)

HTML
<button onclick="alert('この方法は使わないでください')">クリック</button>

HTML と JS が混在し、メンテナンスが困難です。非推奨です。

2. DOM プロパティ

HTML
<button id="myBtn">クリック</button>
<script>
const btn = document.getElementById('myBtn');
btn.onclick = function() {
  console.log('クリックされました');
};
</script>

HTML と JS は分離されますが、各イベントには1つのハンドラしか持てません。後からの代入は以前のものを上書きします。

3. addEventListener(推奨)

HTML
<button id="btn1">ボタン 1</button>
<button id="btn2">ボタン 2</button>
<script>
const btn1 = document.getElementById('btn1');
const btn2 = document.getElementById('btn2');
btn1.addEventListener('click', function() {
  console.log('ハンドラ 1');
});
btn1.addEventListener('click', function() {
  console.log('ハンドラ 2');
});
</script>

同じイベントに複数のハンドラを持たせることができ、removeEventListener で削除することもできます。最も柔軟なアプローチです。

💡 3つの方法の選択肢:最初の2つを忘れ、常に addEventListener を使いましょう。既存のリスナーを上書きせず、バブリング/キャプチャのフェーズを制御できます。現代的な開発での唯一の選択肢です。


addEventListener と removeEventListener

HTML
<script>
element.addEventListener('eventName', handler, options);
element.removeEventListener('eventName', handler);
</script>
⚠️ removeEventListener には addEventListener と同じ関数参照が必要です。匿名関数は削除できません!ハンドラを削除する必要がある場合は、関数を別々に定義してください。

HTML
<button id="btn">テスト</button>
<script>
const btn = document.getElementById('btn');

function handler() { console.log('1回だけトリガーされます'); }
btn.addEventListener('click', handler);
btn.removeEventListener('click', handler);  // 削除成功

btn.addEventListener('click', function() { console.log('匿名'); });
btn.removeEventListener('click', function() { console.log('匿名'); });  // 削除失敗!
</script>

一般的なイベントタイプ

カテゴリ イベント 説明
マウス clickdblclick シングルクリック、ダブルクリック
マウス mouseovermouseout マウスが入る/出る
キーボード keydownkeyup キーが押された/離された
フォーム submit フォームが送信された
フォーム change フォーカスを失った後に値が変更された
フォーム input 値がリアルタイムで変更される(各文字入力ごと)
ページ load ページとすべてのリソースが完全に読み込まれた
ページ DOMContentLoaded HTML の解析が完了(画像を待たない)
💡 change vs inputinput は入力中に発火し、change は入力完了後にフォーカスを失った時に発火します。リアルタイム検索には input を、フォームバリデーションには change を使いましょう。


イベントオブジェクト

イベントハンドラはイベントオブジェクトのパラメータを受け取ります。通常 event または省略形の e と呼ばれます。

プロパティ/メソッド 説明
e.target イベントをトリガーした要素(実際にクリックされたもの)
e.type イベントタイプ(例:'click'
e.preventDefault() デフォルト動作を防止(例:リンクのナビゲーション、フォームの送信を防止)
e.stopPropagation() イベントのバブリングを停止

例:ボタンクリックカウンター

HTML
<button id="counter">0 回クリック</button>

<script>
const btn = document.getElementById('counter');
let count = 0;

btn.addEventListener('click', function(e) {
  count++;
  btn.textContent = count + ' 回クリック';
  console.log('イベントタイプ:', e.type);
  console.log('ターゲット要素:', e.target.tagName);
});
</script>
▶ 試してみよう

例:キーボード検出

<p>任意のキーを押して情報を確認してください</p>
<div id="info" style="padding: 10px; border: 1px solid #ccc; min-height: 30px;"></div>

<script>
const info = document.getElementById('info');

document.addEventListener('keydown', function(e) {
  info.innerHTML = 'キー: <b>' + e.key + '</b> | KeyCode: ' + e.keyCode + ' | Ctrl: ' + e.ctrlKey + ' | Shift: ' + e.shiftKey;
});
</script>
▶ 試してみよう

例:フォームのインターセプト

HTML
<form id="myForm">
  <input type="text" id="name" placeholder="名前を入力" required>
  <button type="submit">送信</button>
</form>
<p id="result"></p>

<script>
const form = document.getElementById('myForm');
const result = document.getElementById('result');

form.addEventListener('submit', function(e) {
  e.preventDefault();
  const name = document.getElementById('name').value;
  result.textContent = 'こんにちは、' + name + 'さん!フォームはインターセプトされ、実際には送信されませんでした。';
});
</script>
▶ 試してみよう

例:イベント委譲

HTML
<ul id="menu">
  <li>ホーム</li>
  <li>概要</li>
  <li>お問い合わせ</li>
  <li>ヘルプ</li>
</ul>
<p id="selected"></p>

<script>
const menu = document.getElementById('menu');
const selected = document.getElementById('selected');

menu.addEventListener('click', function(e) {
  if (e.target.tagName === 'LI') {
    selected.textContent = '選択しました: ' + e.target.textContent;
  }
});
</script>
▶ 試してみよう
💡 上記のテクニックは「イベント委譲」と呼ばれます。リスナーを親要素にバインドし、e.target を使ってどの子要素が実際にクリックされたかを判定します。各 li に個別にイベントをバインドする必要はなく、新しい子要素も自動的に動作します。これがバブリングメカニズムの力です。


イベントのバブリングとキャプチャ

DOM イベントの伝播には3つのフェーズがあります。

  1. キャプチャフェーズ:イベントが window から下方向にターゲット要素へ移動
  2. ターゲットフェーズ:イベントが実際のトリガー要素に到達
  3. バブリングフェーズ:イベントがターゲット要素から上方向に window へ戻る

デフォルトでは、addEventListener はバブリングフェーズでトリガーされます。第3パラメータを true に設定すると、キャプチャフェーズでトリガーされます。

     window
       ↓ キャプチャ
    document
       ↓
      body
       ↓
   ターゲット要素 ← ターゲットフェーズ
       ↑ バブリング
      body
       ↑
    document
       ↑
     window
💡 ほとんどの場合、キャプチャを気にする必要はありません。デフォルトのバブリングで十分です。e.stopPropagation() はイベントの伝播を停止できますが、過度に使うとイベント委譲が壊れる可能性があります。


📖 まとめ

  1. 3つのバインド方法の中で、addEventListener だけが推奨されます。複数のリスナーに対応し、削除可能で、伝播フェーズを制御できます。
  2. removeEventListener には同じ関数参照が必要です。匿名関数は削除できません。
  3. コアイベントオブジェクト e のプロパティ:target(誰がトリガーしたか)、type(何のイベントか)、preventDefault()(デフォルト動作を防止)、stopPropagation()(伝播を停止)。
  4. change vs input:前者はブラー時に発火、後者はリアルタイムで発火。
  5. イベントバブリングにより「イベント委譲」が可能に。親でリスニングし、e.target で子を処理。
  6. DOMContentLoadedload より早く発火し、DOM の初期化に適している。

❓ よくある質問

Q e.targete.currentTarget の違いは何ですか?
A e.target はイベントを実際にトリガーした要素(クリックしたもの)、e.currentTarget は現在ハンドラを実行している要素(リスナーを持っているもの)です。イベント委譲では異なり、直接バインドでは同じです。
Q フォーム送信後にページが更新されるのはなぜですか?
A <form>submit イベントのデフォルト動作は送信とページの更新です。e.preventDefault() を呼び出して防止し、JS でデータを処理しましょう。
Q onclickaddEventListener('click') を一緒に使えますか?
A はい、ただし onclick の代入は以前に onclick でバインドされた関数を上書きしますが、addEventListener は上書きしません。混在させると混乱するので、安心のために addEventListener に統一しましょう。

📝 演習

  1. 基礎:ボタンを作成し、addEventListenerclick イベントをバインドしてください。クリックごとにボタンの幅が10px 増加するようにしてください。
  2. 中級:キーボード楽器を実装してください。keydown イベントをリスニングし、A/S/D/F/G が押された時にページに異なる音階名(ド/レ/ミ/ファ/ソ)を表示してください。
  3. チャレンジ:イベント委譲を使って動的メニューを実装してください。「アイテム追加」ボタン付きの ul リスト。新しく追加された li アイテムもクリック時にハイライトされるようにしてください(新しい li 要素に個別にイベントをバインドする必要はありません)。
  4. ボーナスinput イベントでリアルタイム検索を実装してください。入力フィールドに入力すると、下のリストに入力テキストを含むアイテムのみが表示されます。
100%