Lompat ke konten
Kembali ke modul

Browser: HTML, CSS, DOM, dan Aksesibilitas · 7/8

Event, bubbling, dan delegation

Bagaimana sebuah klik berjalan melewati halamanmu, dan kenapa itu penting nanti di React.

Baca 25 menit

Setelah pelajaran ini kamu bisa

  • Menjelaskan tiga fase yang dilalui sebuah event
  • Menjelaskan bedanya bubbling dan capturing
  • Memakai event delegation, dan menjelaskan kenapa ia lebih skalabel
  • Memilih dengan tepat antara `preventDefault` dan `stopPropagation`

Klik sebuah button di dalam kartu di dalam list, dan klik itu tidak hanya terjadi pada button-nya. Ia berjalan — turun dari dokumen ke button, lalu kembali naik. Memahami perjalanan itu menjelaskan delegation, dan menjelaskan seluruh sistem event React.

FaseArahListener yang aktif
1. Capturedocument → targetHanya yang didaftarkan dengan capture: true
2. Targetdi elemennya sendiriSemua listener pada target-nya
3. Bubbletarget → documentYang biasa — ini default-nya
Coba sendiri

Propagasi lengkap, diimplementasikan. Ubah `stopAt` untuk melihat apa yang sebenarnya dihentikan stopPropagation.

Hasil

Tekan Jalankan untuk melihat hasilnya.

Ini jalan di browser kamu, di dalam sandbox. Apa pun yang kamu tulis di sini tidak bisa merusak situs.

Perhatikan listener bubble terakhir: close-menus-on-outside-click di document. Pola itu ada di mana-mana, dan itu sebabnya satu stopPropagation() yang sembarangan merusak fitur yang tidak berhubungan — listener di document-nya sama sekali tidak mendengar klik itu.

preventDefault versus stopPropagation

MethodMenghentikanDipakai untuk
preventDefault()Reaksi bawaan browserMencegah form ter-submit atau link berpindah halaman
stopPropagation()Event berjalan lebih jauhMencegah handler leluhurnya ikut aktif
js
// Handle a form in JavaScript instead of a full page reload.
form.addEventListener("submit", (event) => {
  event.preventDefault();          // the browser would navigate otherwise
  save(new FormData(form));
});

// A delete button inside a clickable card: do not also open the card.
deleteButton.addEventListener("click", (event) => {
  event.stopPropagation();         // the card's handler must not fire
  remove();
});

Delegation

Karena event ber-bubble, kamu bisa memasang satu listener di container alih-alih satu per anak. event.target memberitahumu apa yang sebenarnya diklik.

js
// One listener for a list of any length, including rows added later.
document.querySelector(".venues").addEventListener("click", (event) => {
  // closest() walks up from the target looking for a match.
  const button = event.target.closest("[data-action]");
  if (!button) return;                    // clicked the gap between items

  const card = button.closest(".card");
  const action = button.dataset.action;

  if (action === "delete") remove(card.dataset.venueId);
  if (action === "favourite") favourite(card.dataset.venueId);
});
event.target adalah yang diklik; event.currentTarget adalah elemen yang listener-nya sedang jalan. Menukar keduanya adalah bug yang umum.
Coba sendiri

Pencocokan delegation, dengan `closest()` yang diimplementasikan. Inilah sebabnya satu listener bisa melayani seribu baris.

Hasil

Tekan Jalankan untuk melihat hasilnya.

Ini jalan di browser kamu, di dalam sandbox. Apa pun yang kamu tulis di sini tidak bisa merusak situs.

Tugas praktik

Di console browser, jalankan ini lalu klik di mana pun di halaman: document.addEventListener("click", e => console.log(e.target.tagName, "->", e.currentTarget === document)). Klik sebuah button, lalu klik teks di dalamnya. Perhatikan target-nya berubah tapi currentTarget-nya selalu document. Muat ulang untuk menghapus listener-nya.

Hasil yang diharapkan

Nama tag target berbeda-beda, currentTarget selalu true.

Cek pemahaman

Kamu memakai delegation untuk klik di sebuah list. Pengguna mengklik ikon <svg> di dalam sebuah button. Apa yang harus dilakukan handler-mu?

Pilih jawaban dulu