Event Bubbling (Bubble Phase)
Event เริ่มที่ Target Element แล้ว "ฟองน้ำ" ขึ้นไปยัง Ancestors จนถึง Window (Default Behavior)
ตัวอย่าง: Nested Elements (Div → Span → Button)
<style>
.styleClass { display: table-cell; border: 1px solid black; padding: 20px; text-align: center; }
</style>
<body>
<div class="styleClass" onclick="alert('Div clicked')"> Div element
<span class="styleClass" onclick="alert('Span clicked')"> span element
<input type="button" value="click me" onclick="alert('Button clicked')">
</span>
</div>
</body>
พฤติกรรม: คลิก Button (Innermost)
- Alert:
Button clicked(Target) - Alert:
Span clicked(Parent) - Alert:
Div clicked(Grandparent)
Event Delegation (Pattern ยอดนิยม)
แทนที่จะ Attach Listener ทุก Child ให้ Attach ที่ Parent แล้วเช็ก event.target
<ul id="list">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
<script>
document.getElementById('list').addEventListener('click', e => {
if (e.target.tagName === 'LI') {
console.log('Clicked:', e.target.textContent);
}
});
</script>
หยุด Bubbling
element.addEventListener('click', e => {
e.stopPropagation(); // หยุด Bubble (แต่ Capture ยังทำงาน)
// e.stopImmediatePropagation(); // หยุด Listener อื่นบน Element เดียวด้วย
});
Capture + Bubble Flow
Window ↓ Capture Phase (useCapture=true) Document ↓ Div (Handler if capture) ↓ Span (Handler if capture) ↓ Button (Target Phase) ↑ Span (Handler if bubble) ← Default ↑ Div (Handler if bubble) ↑ Document ↑ Window
Best Practice
- ใช้ Bubble Phase (Default) สำหรับ General Handling
- ใช้ Event Delegation สำหรับ Dynamic Children / Performance
- ใช้ Capture Phase เฉพาะ Preprocessing/Analytics
stopPropagation()เฉพาะเมื่อจำเป็น (Break Delegation)