【JavaScript】クリックイベントの設定方法|addEventListener・event オブジェクト・バブリング・イベント委任・実務パターンまで解説

ボタンのクリック、リンクのタップ、カードの選択など、クリックイベントは Web アプリケーションで最も基本的なユーザー操作です。JavaScript の addEventListener を使えば、任意の HTML 要素にクリック時の処理を設定できます。

この記事でわかること
・addEventListener でクリックイベントを設定する方法
・onclick 属性・onclick プロパティとの違い
・event オブジェクトの活用(target・currentTarget・preventDefault)
・バブリングとキャプチャリングの仕組み
・イベント委任(Event Delegation)で動的要素に対応する方法
・once・passive オプション
・ダブルクリック・右クリックの検出
・トグル切り替え・モーダル開閉・連打防止の実務パターン
スポンサーリンク

addEventListener でクリックイベントを設定する

HTML
<button id="myBtn">クリック</button>
JavaScript
const btn = document.getElementById("myBtn");

btn.addEventListener("click", () => {
  console.log("クリックされました");
});

第 1 引数にイベント名("click")、第 2 引数にコールバック関数を渡します。

クリックイベントを設定する 3 つの方法と違い

方法 コード例 複数登録 推奨度
addEventListener el.addEventListener("click", fn) ○ 可能 ★★★ 推奨
onclick プロパティ el.onclick = fn × 上書きされる ★★
HTML 属性 <button onclick="fn()"> × 1 つのみ ★ 非推奨
addEventListener: 複数登録できる
const btn = document.getElementById("myBtn");

// 2つのリスナーを同じ要素に登録できる
btn.addEventListener("click", () => console.log("処理A"));
btn.addEventListener("click", () => console.log("処理B"));
// クリック時: "処理A" → "処理B"(両方実行される)
onclick プロパティ: 後から上書きされる
const btn = document.getElementById("myBtn");

btn.onclick = () => console.log("処理A");
btn.onclick = () => console.log("処理B"); // 処理Aが消える
// クリック時: "処理B" のみ
現代の JavaScript では常に addEventListener を使いましょう。複数のリスナーを同じ要素に登録でき、oncepassive などのオプションも設定できます。

event オブジェクトを活用する

コールバック関数の引数として event オブジェクトが渡されます。クリック位置、クリックされた要素、デフォルト動作の抑止などに使います。

プロパティ / メソッド 説明
event.target 実際にクリックされた要素
event.currentTarget リスナーが登録されている要素
event.preventDefault() デフォルト動作を抑止(リンク遷移・フォーム送信など)
event.stopPropagation() イベントの伝播(バブリング)を停止
event.clientX / clientY クリック位置(ビューポート基準)
event.button 押されたボタン(0=左, 1=中, 2=右)
target と currentTarget の違い
<div id="parent">
  <button id="child">クリック</button>
</div>
JavaScript
document.getElementById("parent").addEventListener("click", (e) => {
  console.log("target:", e.target.id);        // "child"(実際にクリックされた要素)
  console.log("currentTarget:", e.currentTarget.id); // "parent"(リスナーが付いた要素)
});

preventDefault でデフォルト動作を抑止する

JavaScript
// リンクのクリックでページ遷移を防ぐ
document.querySelector("a.no-navigate").addEventListener("click", (e) => {
  e.preventDefault();
  console.log("遷移しません");
});

// フォームの送信を防いで独自処理
document.getElementById("myForm").addEventListener("submit", (e) => {
  e.preventDefault();
  // 非同期送信などの独自処理
});

バブリングとキャプチャリング

クリックイベントは、クリックされた要素から親要素に向かって伝播します(バブリング)。逆に、document から子要素に向かう伝播がキャプチャリングです。

バブリングの例
<div id="outer">
  <div id="inner">
    <button id="btn">クリック</button>
  </div>
</div>
JavaScript
document.getElementById("btn").addEventListener("click", () => console.log("btn"));
document.getElementById("inner").addEventListener("click", () => console.log("inner"));
document.getElementById("outer").addEventListener("click", () => console.log("outer"));

// ボタンをクリックすると:
// "btn" → "inner" → "outer"(子→親の順に伝播)
stopPropagation でバブリングを停止
document.getElementById("btn").addEventListener("click", (e) => {
  e.stopPropagation(); // 親要素への伝播を停止
  console.log("btn のみ実行");
});

// ボタンをクリック → "btn のみ実行"(inner, outer は実行されない)

イベント委任(Event Delegation)

動的に追加される要素にもイベントを適用するには、親要素にリスナーを 1 つだけ設定し、event.target で判定するイベント委任パターンが有効です。

JavaScript
const list = document.getElementById("todoList");

// 親要素に1つだけリスナーを設定
list.addEventListener("click", (e) => {
  // クリックされた要素が削除ボタンか判定
  if (e.target.matches(".delete-btn")) {
    e.target.closest("li").remove();
  }
});

// 後から追加した li 内の .delete-btn もイベントが動作する
function addItem(text) {
  list.insertAdjacentHTML(
    "beforeend",
    `<li>${text} <button class="delete-btn">削除</button></li>`
  );
}
イベント委任を使うと、リスナーの数が最小限になりパフォーマンスが向上します。動的に要素を追加・削除するアプリでは必須のテクニックです。

once・passive オプション

オプション 説明 用途
once: true 1 回実行後に自動的にリスナーを削除 初回のみの処理(チュートリアル表示など)
passive: true preventDefault を呼ばないことを宣言 スクロール・タッチイベントの最適化
capture: true キャプチャフェーズでリスナーを実行 親要素で先にイベントを処理
JavaScript
// 1回だけ実行されるリスナー
document.getElementById("welcomeBtn").addEventListener("click", () => {
  console.log("ようこそ!(この処理は1回だけ)");
}, { once: true });

ダブルクリック・右クリックの検出

イベント 検出する操作
"click" 左クリック(シングル)
"dblclick" ダブルクリック
"contextmenu" 右クリック(コンテキストメニュー)
"auxclick" 中クリック(ホイールクリック)
JavaScript
// ダブルクリックで編集モードに切り替え
document.getElementById("text").addEventListener("dblclick", (e) => {
  e.target.contentEditable = true;
  e.target.focus();
});

// 右クリックメニューをカスタマイズ
document.getElementById("canvas").addEventListener("contextmenu", (e) => {
  e.preventDefault(); // デフォルトの右クリックメニューを抑止
  showCustomMenu(e.clientX, e.clientY);
});

リスナーを削除する(removeEventListener)

JavaScript
function handleClick() {
  console.log("クリック!");
}

const btn = document.getElementById("myBtn");

// 登録
btn.addEventListener("click", handleClick);

// 削除(同じ関数参照を渡す必要がある)
btn.removeEventListener("click", handleClick);
removeEventListener同じ関数参照を渡さないと削除できません。匿名関数(アロー関数を直接書く)で登録した場合は削除できないため、削除が必要なリスナーは名前付き関数で定義してください。

実務でよく使うパターン

クラスのトグル切り替え

JavaScript
document.getElementById("toggleBtn").addEventListener("click", () => {
  document.getElementById("menu").classList.toggle("is-open");
});

モーダルの開閉

JavaScript
const modal = document.getElementById("modal");
const overlay = document.getElementById("overlay");

// 開く
document.getElementById("openBtn").addEventListener("click", () => {
  modal.classList.add("is-open");
  overlay.classList.add("is-open");
});

// 閉じる(オーバーレイクリック)
overlay.addEventListener("click", () => {
  modal.classList.remove("is-open");
  overlay.classList.remove("is-open");
});

連打防止(デバウンス)

JavaScript
const submitBtn = document.getElementById("submitBtn");

submitBtn.addEventListener("click", () => {
  // ボタンを無効化
  submitBtn.disabled = true;
  submitBtn.textContent = "送信中...";

  // 送信処理(API呼び出しなど)
  fetch("/api/submit", { method: "POST" })
    .then(res => res.json())
    .then(data => {
      submitBtn.textContent = "送信完了";
    })
    .catch(() => {
      // エラー時はボタンを再有効化
      submitBtn.disabled = false;
      submitBtn.textContent = "再送信";
    });
});

関連記事

よくある質問

QaddEventListener と onclick はどちらを使うべきですか?
AaddEventListener を使いましょう。onclick プロパティは 1 つしか登録できず後から上書きされます。addEventListener は複数登録でき、once / passive オプションも使えます。
Qevent.target と event.currentTarget の違いは?
Atarget実際にクリックされた要素currentTargetリスナーが登録されている要素です。イベント委任で親要素にリスナーを付けた場合、target は子要素、currentTarget は親要素になります。
Q動的に追加した要素にクリックイベントが効きません。
AaddEventListener は呼び出し時点で存在する要素にしか設定されません。動的要素にはイベント委任を使ってください。親要素にリスナーを設定し、e.target.matches(".class") でクリックされた要素を判定します。
Q1回だけ実行されるクリックイベントを設定するには?
AaddEventListener("click", fn, { once: true }) で 1 回実行後に自動的にリスナーが削除されます。従来の removeEventListener を自分で呼ぶ方法より簡潔です。
Qスマホでクリックイベントが反応しません。
Aスマホでは click イベントは動作しますが、cursor: pointer が設定されていない非インタラクティブ要素(div・span)では反応しないことがあります。CSS で cursor: pointer を追加するか、button 要素を使ってください。

まとめ

JavaScript でクリックイベントを扱う方法を整理しました。

  • 基本: el.addEventListener("click", fn) でリスナーを登録
  • event オブジェクト: target・preventDefault・stopPropagation を活用
  • バブリング: 子→親に伝播する。stopPropagation で停止可能
  • イベント委任: 親要素に 1 つだけリスナーを設定し、動的要素にも対応
  • オプション: once(1回のみ)、passive(最適化)、capture(キャプチャフェーズ)
  • 削除: removeEventListener には同じ関数参照が必要

クリックイベントは Web アプリのインタラクションの基礎です。イベント委任と once オプションを使いこなすことで、効率的でメンテナブルなコードを書けるようになります。