Event Delegation — ผูก listener ครั้งเดียวกับ parent
แทนที่จะผูก event listener กับทุก element ให้ผูกครั้งเดียวกับ parent แล้วใช้ event.target เลือก element ที่คลิก — ลด memory และรองรับ dynamic elements อัตโนมัติ
// แบบไม่ดี — N listeners สำหรับ N items
document.querySelectorAll('.btn-delete').forEach((btn) => {
btn.addEventListener('click', handleDelete);
});
// แบบดี — 1 listener บน parent
document.querySelector('#list').addEventListener('click', (event) => {
const btn = event.target.closest('.btn-delete');
if (!btn) return; // คลิกที่อื่น — ไม่ทำอะไร
const id = btn.dataset.id;
handleDelete(id);
});
closest() เดิน DOM ขึ้นไปหา ancestor ที่ match selector — สำคัญเมื่อ button มี icon ข้างใน แล้ว event.target อาจเป็น <svg> ไม่ใช่ <button>
กรณีที่ดีที่สุดสำหรับ delegation:
- List item ที่เพิ่ม/ลบ dynamically (
innerHTMLหรือ framework) - Table row ที่มี action buttons หลาย column
- Virtual scroll ที่ re-render DOM