導入
フロントエンド開発において、イベントハンドリングは避けて通れません。特に、リスト要素や動的に生成されるDOMに対して一つずつイベントリスナーを登録するのは、メモリの無駄遣いであり、パフォーマンス低下の原因にもなります。本記事では、Event.targetを活用した「イベント委譲(Event Delegation)」の手法を解説します。これを習得することで、コードの保守性が高まり、動的なDOM操作にも柔軟に対応できるようになります。
基礎知識
Event.targetとは、イベントが発生した「まさにその要素」を指すプロパティです。これに対し、Event.currentTargetは「イベントリスナーが登録されている要素」を指します。
イベントは親要素に向かって伝播する「バブリング」という性質を持っています。この仕組みを利用し、子要素それぞれにリスナーを付けるのではなく、親要素に一つだけリスナーを登録し、Event.targetを使って「どの要素がクリックされたか」を判定するのがイベント委譲です。
実装/解決策
イベント委譲を実装する際は、Event.targetが期待する要素(例えばボタンやリスト項目)であるかを確認する処理が重要です。具体的には、matchesメソッドを使ってターゲットを検証します。これにより、特定のクラスやタグを持つ要素のみに反応させることが可能です。
サンプルプログラム
以下のコードは、親となるul要素に一つだけイベントを登録し、動的に追加されたli要素のクリックも検知する実装例です。
// HTML構造: <ul id="list"><li>項目1</li></ul>
const list = document.getElementById('list');
list.addEventListener('click', (event) => {
// event.targetは「実際にクリックされた要素」を取得
const target = event.target;
// matchesメソッドで、特定のセレクタに一致するか確認する
// これにより、ul自体をクリックした場合は無視できる
if (target.matches('li')) {
console.log('クリックされた項目:', target.textContent);
// 特定の処理を実行
target.style.backgroundColor = '#f0f0f0';
}
});
// 新しい要素を動的に追加しても、親のリスナーが検知してくれる
const newLi = document.createElement('li');
newLi.textContent = '項目2';
list.appendChild(newLi);
応用・注意点
現場で活用する際の最大の注意点は、「子要素の中にさらに要素がある場合」です。例えば、liの中にspanタグが含まれていると、Event.targetはspanを指してしまい、matches(‘li’)がfalseになることがあります。
これを回避するには、closestメソッドを使用するのがベストプラクティスです。
修正案:
if (target.closest(‘li’)) { … }
これを使うと、クリックされた要素自体、もしくはその親要素を遡って条件に合うものを探してくれるため、入れ子構造に非常に強くなります。また、イベントハンドラ内では必ず「どの要素がアクションの起点か」を明確に意識し、無駄なリスナーを削除する癖をつけることで、メモリリークを防ぐ堅牢なアプリケーション構築が可能になります。