Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> JavaScript

Event Bubbling ใน JavaScript: การไหลของ Event จากในออกนอก

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)

  1. Alert: Button clicked (Target)
  2. Alert: Span clicked (Parent)
  3. 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)