イベント委譲パターン
1 つの親リスナーで多数の子要素のイベントを処理します。
「イベント委譲パターン」はCoddyKit上の無料JavaScript Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJavaScript Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 JavaScript Academyコースには全4レッスンが含まれています。
すべてを処理する1つのリスナー
イベントデリゲーションとは、個々の子要素に多数のリスナーを設定する代わりに、共通の祖先要素に1つのリスナーを設定する方法です。イベントはバブルするため、親要素はすべての子孫要素からのクリックを受け取れます。
<ul id="menu">
<li>Home</li>
<li>About</li>
<li>Contact</li>
</ul>素朴な方法
デリゲーションを使わない場合は、すべての項目をループしてハンドラーを設定することになります。これは非効率的です。メモリ使用量が増えるうえ、後から追加された要素には対応できません。
document.querySelectorAll("#menu li").forEach((li) => {
li.addEventListener("click", () => console.log(li.textContent));
});デリゲーションを使う方法
代わりに親要素に1つのリスナーを設定し、event.targetを調べて、どの子要素がクリックされたかを確認します。
const menu = document.getElementById("menu");
menu.addEventListener("click", (e) => {
console.log(e.target.textContent);
});正しいターゲットを見つける
クリックは入れ子になった要素上で発生することがあります。event.target.closest(selector)を使って上位の要素をたどり、セレクターに一致する関連する祖先要素を見つけます。
menu.addEventListener("click", (e) => {
const item = e.target.closest("li");
if (!item) return; // clicked outside any li
console.log("Clicked:", item.textContent);
});チェックで保護する
一致しないクリックは必ず処理対象外にしてください。if (!item) return;による早期終了を入れておくと、コンテナー内の余白や隙間をクリックしたときにハンドラーがクラッシュするのを防げます。
menu.addEventListener("click", (e) => {
const item = e.target.closest("li");
if (!item || !menu.contains(item)) return;
handleSelect(item);
});データ属性を使う
各項目にdata-*属性を使ってIDやアクションを保存するのは、よく使われるパターンです。デリゲーションされたハンドラーは、一致した要素からその値を読み取ります。
menu.addEventListener("click", (e) => {
const item = e.target.closest("li");
if (!item) return;
const id = item.dataset.id; // reads data-id
console.log("Selected id:", id);
});アクションで振り分ける
ボタンが多いツールバーでは、それぞれにdata-actionを設定し、その値で分岐します。1つのリスナーですべてのボタンを処理できます。
toolbar.addEventListener("click", (e) => {
const btn = e.target.closest("button");
if (!btn) return;
switch (btn.dataset.action) {
case "save": save(); break;
case "delete": remove(); break;
}
});規模を拡大できる理由
デリゲーションを使えば、1000行のリストでも必要なリスナーは1000個ではなく1個だけです。メモリ使用量を減らし、セットアップを高速化できるうえ、行が変わるたびにクリーンアップするループも必要ありません。
パフォーマンスに関する注意
デリゲーションにも小さなコストはあります。一致するイベントが発生するたびにハンドラーが実行され、その後でフィルタリングするためです。ほとんどのアプリでは節約できるコストと比べて無視できる程度ですが、mousemoveのような高頻度イベントに対してdocumentへデリゲーションされたリスナーを設定するのは避けてください。
コンテナーを選ぶ
すべての対象を含む、最も近い安定した祖先要素を選びます。documentにデリゲーションするよりも、リスト自体のような範囲の狭いコンテナーにデリゲーションするほうが適しています。無関係なイベントによってハンドラーが実行される回数を減らせるためです。
const list = document.querySelector(".task-list");
list.addEventListener("click", onTaskClick);closest と組み合わせる
closest()はデリゲーションの中心となるメソッドです。呼び出した要素自身が一致すればその要素を、一致しなければ最も近い一致する祖先要素を返し、どちらもなければnullを返します。これにより、入れ子になったマークアップにも安全にデリゲーションを使えます。
const cell = e.target.closest("td[data-col]");
if (cell) console.log(cell.dataset.col);確認問題
なぜイベントデリゲーションを使うのでしょうか。
まとめ
イベントデリゲーションでは、親要素に1つのリスナーを設定し、バブリングを利用してすべての子要素を処理します。e.target.closest(selector)で関連する要素を見つけ、早期終了で対象外のクリックを処理し、data-*属性を読み取ってアクションを振り分けます。大量のリストにも対応できる、動的なUIの標準的なパターンです。
よくある質問
「イベント委譲パターン」レッスンは無料ですか?
はい。「イベント委譲パターン」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、JavaScript Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 JavaScript Academyコースには全4レッスンが含まれています。
「イベント委譲パターン」で何を学びますか?
1 つの親リスナーで多数の子要素のイベントを処理します。 ブラウザで直接実行するハンズオンコードでJavaScript Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
JavaScript Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのJavaScript Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。
「イベント委譲パターン」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このJavaScript Academyレッスンでコードを書いて実行できますか?
はい。すべてのJavaScript Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- キャプチャフェーズとバブリングフェーズ
- イベント委譲パターン
- 委譲を使った動的リスト
- カスタムイベント