同じボタンが一覧の中にたくさんあるとき、要素ごとに addEventListener を付けるより、親要素でまとめてイベントを受け取る方が扱いやすいことがあります。この考え方をイベント委譲と呼びます。
WordPressの記事一覧、タグフィルター、アコーディオン、削除ボタン付きリストなど、あとから要素が増えるUIでは特に便利です。
HTML
<ul class="todo-list" id="todo-list">
<li><button type="button" data-action="done">完了</button> 練習メニューを書く</li>
<li><button type="button" data-action="done">完了</button> 記事を公開する</li>
<li><button type="button" data-action="done">完了</button> 内部リンクを確認する</li>
</ul>
JavaScript
const list = document.querySelector("#todo-list");
list.addEventListener("click", (event) => {
const button = event.target.closest("[data-action='done']");
if (!button || !list.contains(button)) {
return;
}
const item = button.closest("li");
item.classList.toggle("is-done");
});
CSS
.todo-list {
display: grid;
gap: 10px;
padding-left: 0;
list-style: none;
}
.todo-list li {
padding: 12px;
border: 1px solid #d1d5db;
border-radius: 6px;
}
.todo-list li.is-done {
color: #6b7280;
text-decoration: line-through;
background: #f3f4f6;
}
なぜ親要素で受け取れるのか
クリックイベントは、実際に押された要素から親要素へ伝わっていきます。親の ul でイベントを受け取り、event.target.closest() で押されたボタンを探せば、子要素ごとに処理を書かずに済みます。
使うときの注意点
closest()で対象要素を絞るcontains()で親要素の中のクリックか確認する- 何でもdocumentで受けず、できるだけ近い親要素で受ける
- 複雑になったら
data-actionで処理を分ける