委譲を使った動的リスト
実行時に追加された要素のイベントを管理します。
「委譲を使った動的リスト」はCoddyKit上の無料JavaScript Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJavaScript Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 JavaScript Academyコースには全4レッスンが含まれています。
動的な要素の問題
要素に直接リスナーを設定すると、セットアップの後にDOMへ追加された要素にはリスナーがありません。デリゲーションなら、親要素のリスナーが後から追加された子要素のイベントも受け取るため、この問題を解決できます。
直接設定したリスナーが機能しない理由
ここでは、既存の項目にリスナーを追加しています。後から追加された項目には何も設定されないため、機能しないままです。
document.querySelectorAll(".item").forEach((el) =>
el.addEventListener("click", handle)
);
list.appendChild(newItem); // newItem has NO handlerデリゲーションならそのまま動く
親要素にデリゲーションされたリスナーを設定しておけば、新しい項目も自動的に処理されます。項目を挿入するたびにリスナーを再設定する必要はありません。
list.addEventListener("click", (e) => {
const item = e.target.closest(".item");
if (item) console.log("Clicked", item.dataset.id);
});
list.appendChild(newItem); // works immediately項目を追加する
新しい要素を作成して追加します。親要素ではすでにデリゲーションが設定されているため、追加された瞬間から操作できるようになります。
function addItem(text) {
const li = document.createElement("li");
li.className = "item";
li.textContent = text;
list.appendChild(li);
}項目を削除する
削除も簡単です。デリゲーションされたハンドラーで行内の削除ボタンを検出し、その行を削除できます。
list.addEventListener("click", (e) => {
if (e.target.matches(".delete-btn")) {
e.target.closest(".item").remove();
}
});サブアクションを区別する
1つの行に複数の操作可能な部分が含まれることがあります。matches()やclosest()を使ってどの部分がクリックされたかを判別し、それに応じて分岐します。
list.addEventListener("click", (e) => {
if (e.target.matches(".edit-btn")) edit(e);
else if (e.target.matches(".delete-btn")) del(e);
});データから描画する
よく使われるパターンは、配列に状態を保持し、そこから行を描画して、クリックをデリゲーションで処理する方法です。再描画によって子要素が置き換えられても、親要素の1つのリスナーはそのまま残ります。
function render(items) {
list.innerHTML = items
.map((i) => "<li class=\"item\" data-id=\"" + i.id + "\">" + i.name + "</li>")
.join("");
}クリーンアップに悩まされない
要素ごとにリスナーを設定する場合、メモリリークを避けるため、ノードを削除する前にremoveEventListenerを呼び出す必要があります。デリゲーションならこの負担がなく、子要素を削除しても孤立したリスナーは発生しません。
クラスを切り替える
デリゲーションは、選択状態を表すクラスの切り替えと相性が良い方法です。ハンドラーで行を見つけ、そのクラスを切り替えます。
list.addEventListener("click", (e) => {
const row = e.target.closest(".item");
if (row) row.classList.toggle("selected");
});安定した識別子を読み取る
再描画ではDOMノードが置き換えられるため、ノードへの参照を保存しないでください。data-idに変わらないIDを保存し、ハンドラー内でそのIDを使ってデータモデルを検索します。
const id = e.target.closest(".item").dataset.id;
const record = state.find((r) => r.id === id);入力イベントにも使える
デリゲーションはクリックに限られません。動的に追加されるフォームフィールドのinputイベントやchangeイベントにも、同じ方法でデリゲーションを使えます。
form.addEventListener("input", (e) => {
if (e.target.matches(".qty")) recalc(e.target);
});確認問題
動的なリストとデリゲーションについて確認します。
まとめ
デリゲーションは動的なリストで特に効果を発揮します。1つの親リスナーで現在と将来の子要素を処理でき、再描画後も機能し、ノードごとのクリーンアップも必要ありません。matches()とclosest()を使ってサブアクションを振り分け、data-*に変わらないIDを保存して、ハンドラーからデータモデルを見つけられるようにします。
よくある質問
「委譲を使った動的リスト」レッスンは無料ですか?
はい。「委譲を使った動的リスト」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、JavaScript Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 JavaScript Academyコースには全4レッスンが含まれています。
「委譲を使った動的リスト」で何を学びますか?
実行時に追加された要素のイベントを管理します。 ブラウザで直接実行するハンズオンコードでJavaScript Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
JavaScript Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのJavaScript Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。
「委譲を使った動的リスト」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このJavaScript Academyレッスンでコードを書いて実行できますか?
はい。すべてのJavaScript Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- キャプチャフェーズとバブリングフェーズ
- イベント委譲パターン
- 委譲を使った動的リスト
- カスタムイベント