組み込み関数

JavaScriptのイベント処理入門|イベントの仕組みと活用方法

イベント処理は、ユーザーの操作(クリック、入力、スクロールなど)に応じてJavaScriptのコードを実行する仕組みです。インタラクティブなWebページを作るための基本技術で、DOM操作と並んでフロントエンド開発の必須スキルです。

基本的な使い方

addEventListener()で要素にイベントリスナーを登録します。イベントが発生すると、指定したコールバック関数が実行されます。

JavaScript
// イベントリスナーの登録
const button = document.querySelector("#myButton");

button.addEventListener("click", function(event) {
  console.log("ボタンがクリックされました");
  console.log("対象要素:", event.target.tagName);
});

// アロー関数で書く場合
button.addEventListener("click", (e) => {
  console.log("クリック位置:", e.clientX, e.clientY);
});

// イベントリスナーの削除
function handleClick() {
  console.log("1回だけ実行");
  button.removeEventListener("click", handleClick);
}
button.addEventListener("click", handleClick);

// onceオプション(1回だけ実行してから自動削除)
button.addEventListener("click", () => {
  console.log("1回だけ実行(once)");
}, { once: true });
実行結果
ボタンがクリックされました
対象要素: BUTTON
クリック位置: 150 200
1回だけ実行
1回だけ実行(once)

よく使うイベントの種類

マウス、キーボード、フォーム、ウィンドウなど、さまざまなイベントを処理できます。

JavaScript
// マウスイベント
element.addEventListener("click", handler);     // クリック
element.addEventListener("dblclick", handler);   // ダブルクリック
element.addEventListener("mouseenter", handler); // マウスが乗った
element.addEventListener("mouseleave", handler); // マウスが離れた

// キーボードイベント
document.addEventListener("keydown", (e) => {
  console.log("キー:", e.key, "コード:", e.code);
  if (e.key === "Escape") console.log("Escキーが押されました");
  if (e.ctrlKey && e.key === "s") {
    e.preventDefault(); // ブラウザのデフォルト動作を抑止
    console.log("Ctrl+S: 保存処理を実行");
  }
});

// フォームイベント
const input = document.querySelector("input");
input.addEventListener("input", (e) => {
  console.log("入力値:", e.target.value);
});
input.addEventListener("change", (e) => {
  console.log("確定値:", e.target.value);
});
input.addEventListener("focus", () => console.log("フォーカス"));
input.addEventListener("blur", () => console.log("フォーカス外れた"));

// フォーム送信
const form = document.querySelector("form");
form.addEventListener("submit", (e) => {
  e.preventDefault(); // ページ遷移を防止
  const formData = new FormData(form);
  console.log("送信データ:", Object.fromEntries(formData));
});
実行結果
キー: Escape コード: Escape
Escキーが押されました
入力値: テスト
確定値: テスト入力
フォーカス
フォーカス外れた

イベントの委任(Event Delegation)

イベントの委任は、子要素のイベントを親要素で一括して処理するパターンです。動的に追加される要素にも対応でき、パフォーマンスも向上します。

JavaScript
// イベントの委任(Event Delegation)
const todoList = document.querySelector("#todo-list");

// 親要素にリスナーを1つだけ登録
todoList.addEventListener("click", (e) => {
  // クリックされた要素がボタンか判定
  if (e.target.classList.contains("delete-btn")) {
    const item = e.target.closest("li");
    item.remove();
    console.log("項目を削除しました");
  }

  if (e.target.classList.contains("complete-btn")) {
    const item = e.target.closest("li");
    item.classList.toggle("completed");
    console.log("完了状態を切り替えました");
  }
});

// 動的に追加された要素にも自動で対応
function addTodo(text) {
  const li = document.createElement("li");
  li.innerHTML = `
    ${text}
    
    
  `;
  todoList.appendChild(li);
}

実践的な活用例

JavaScript
// デバウンス付きの検索入力
function debounce(fn, delay) {
  let timer;
  return function(...args) {
    clearTimeout(timer);
    timer = setTimeout(() => fn.apply(this, args), delay);
  };
}

const searchInput = document.querySelector("#search");
searchInput.addEventListener("input", debounce((e) => {
  console.log("検索:", e.target.value);
}, 300));

// スクロール位置の監視
window.addEventListener("scroll", debounce(() => {
  const scrollY = window.scrollY;
  const header = document.querySelector("header");
  if (scrollY > 100) {
    header.classList.add("scrolled");
  } else {
    header.classList.remove("scrolled");
  }
}, 50));

// カスタムイベント
const customEvent = new CustomEvent("userAction", {
  detail: { action: "login", user: "田中" }
});

document.addEventListener("userAction", (e) => {
  console.log("カスタムイベント:", e.detail);
});

document.dispatchEvent(customEvent);
実行結果
カスタムイベント: { action: "login", user: "田中" }
イベントのバブリング

イベントは子要素から親要素に向かって伝播します(バブリング)。event.stopPropagation()で伝播を止めることができます。イベント委任はこのバブリングを利用した技法です。

注意点

addEventListener()で登録したリスナーは、不要になったらremoveEventListener()で削除してください。特にSPAでは、コンポーネント破棄時にリスナーを残すとメモリリークの原因になります。アロー関数で登録したリスナーは参照が異なるため削除できない点にも注意が必要です。

まとめ

  • addEventListener()でイベントリスナーを登録
  • event.preventDefault()でデフォルト動作を抑止
  • イベント委任で動的要素にも対応し、パフォーマンスを向上
  • デバウンスで高頻度イベントの処理を最適化
  • 不要なリスナーはremoveEventListener()で削除する