0Pricing
JavaScript Academy · レッスン

委譲を使った動的リスト

実行時に追加された要素のイベントを管理します。

「委譲を使った動的リスト」は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フィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. キャプチャフェーズとバブリングフェーズ
  2. イベント委譲パターン
  3. 委譲を使った動的リスト
  4. カスタムイベント
← JavaScript Academyに戻る