Tidak dapat memahami parameter useCapture di addEventListener

290

Saya telah membaca artikel di https://developer.mozilla.org/en/DOM/element.addEventListener tetapi tidak dapat memahami useCaptureatribut. Definisi ada:

Jika benar, useCapture menunjukkan bahwa pengguna ingin memulai penangkapan. Setelah memulai penangkapan, semua peristiwa dengan tipe yang ditentukan akan dikirim ke pendengar terdaftar sebelum dikirim ke EventTarget di bawahnya di pohon DOM. Acara yang menggelegak ke atas melalui pohon tidak akan memicu pendengar yang ditunjuk untuk menggunakan tangkapan.

Dalam kode ini peristiwa induk memicu sebelum anak, jadi saya tidak dapat memahami perilakunya. Objek dokumen memiliki usecapture true dan div anak telah usecapture set false dan dokumen usecapture diikuti. Jadi mengapa properti dokumen lebih disukai daripada anak.

function load() {
  document.addEventListener("click", function() {
    alert("parent event");
  }, true);

  document.getElementById("div1").addEventListener("click", function() {
    alert("child event");
  }, false);
}
<body onload="load()">
  <div id="div1">click me</div>
</body>

pengguna26732
sumber

Jawaban:

350

Acara dapat diaktifkan pada dua kesempatan: Di awal ("tangkap"), dan di akhir ("gelembung"). Peristiwa dieksekusi dalam urutan bagaimana mereka didefinisikan. Katakanlah, Anda menetapkan 4 pendengar acara:

window.addEventListener("click", function(){console.log(1)}, false);
window.addEventListener("click", function(){console.log(2)}, true);
window.addEventListener("click", function(){console.log(3)}, false);
window.addEventListener("click", function(){console.log(4)}, true);

Pesan log akan muncul dalam urutan ini:

  • 2(didefinisikan pertama, menggunakan capture=true)
  • 4(didefinisikan menggunakan kedua capture=true)
  • 1(acara pertama yang didefinisikan dengan capture=false)
  • 3(peristiwa yang ditentukan kedua dengan capture=false)
Rob W
sumber
49
Urutan eksekusi tidak dijamin : no specification is made as to the order in which they will receive the event with regards to the other EventListeners on the EventTarget. Saya belum menguji semua browser, jadi mereka semua bisa saja menerapkannya dengan cara yang sama. Namun, acara tangkap akan dilakukan sebelum acara yang tidak diambil.
beatgammit
47
@tjameson Urutan eksekusi adalah dijamin dalam penerus DOM2 spec, peristiwa DOM3 : "pelaksanaannya harus menentukan target saat ini calon pendengar acara ini harus menjadi daftar semua pendengar acara yang telah terdaftar pada target saat ini di mereka. urutan pendaftaran. "
Rob W
1
jadi ini pada dasarnya ada hubungannya dengan urutan acara kurasa
slier
1
@sebelumnya, ya, urutan beberapa penangan untuk acara yang sama dieksekusi.
JMD
6
Tidak tahu mengapa ini adalah jawaban yang diterima sejak afaik, menangkap dan melontarkan pembicaraan tentang perilaku propagasi dan bukan tentang mendikte urutan eksekusi untuk beberapa penangan acara yang berdekatan
georaldc
272

Saya menemukan diagram ini sangat berguna untuk memahami fase penangkapan / target / gelembung: http://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/events.html#Events-phases

Di bawah, konten diekstraksi dari tautan.

Fase

Acara ini dikirim mengikuti jalur dari akar pohon ke simpul target ini. Kemudian dapat ditangani secara lokal di tingkat simpul target atau dari leluhur target mana pun yang lebih tinggi di pohon. Acara pengiriman (juga disebut propagasi acara) terjadi dalam tiga fase dan urutan berikut:

  1. Fase penangkapan: peristiwa dikirim ke nenek moyang target dari akar pohon ke induk langsung dari simpul target.
  2. Fase target: acara dikirim ke node target.
  3. Fase menggelegak: peristiwa dikirim ke nenek moyang target dari induk langsung dari simpul target ke akar pohon.

representasi grafis dari suatu peristiwa yang dikirim dalam pohon DOM menggunakan aliran acara DOM

Nenek moyang target ditentukan sebelum pengiriman awal acara. Jika node target dihapus selama pengiriman, atau leluhur target ditambahkan atau dihapus, propagasi acara akan selalu didasarkan pada node target dan leluhur target ditentukan sebelum pengiriman.

Beberapa peristiwa mungkin tidak perlu mencapai tiga fase dari aliran peristiwa DOM, misalnya acara hanya dapat didefinisikan untuk satu atau dua fase. Sebagai contoh, peristiwa yang ditentukan dalam spesifikasi ini akan selalu mencapai fase penangkapan dan target tetapi beberapa tidak akan mencapai fase gelembung ("peristiwa gelembung" versus "peristiwa non-gelembung", lihat juga atribut Event.bubbles).

lax4mike
sumber
1
diagram yang sangat bagus!
Alex
1
Bagaimana dengan anak-anak dari simpul target? Kapan mereka mendapatkan acara tersebut?
Aurimas
Apakah akar pohon itu sebenarnya Window, bukan document, karena documentanak itu berasal Window?
stackjlei
1
@ Aura mereka tidak, itu tidak masuk akal. Target adalah elemen paling dalam yang harus menerima acara. Jika Anda mengklik elemen <body> (tempat kosong), semua elemen di dalam <body> (= semua elemen halaman) seharusnya tidak menerima acara klik.
amik
1
Saya hanya berharap semua sumber daya yang menjelaskan "apa" termasuk "mengapa". Pergi ke lebih banyak googling seperti biasa.
aaaaaa
80

Capture Event ( useCapture = true) vs Bubble Event ( useCapture = false)

Referensi MDN

  • Capture Event akan dikirim sebelum Bubble Event
  • Urutan propagasi acara adalah
    1. Capture Induk
    2. Penangkapan Anak
    3. Target Capture dan Target Bubble
      • Dalam urutan mereka terdaftar
      • Ketika elemen adalah target acara, useCaptureparameter tidak masalah (Terima kasih @bam dan @ legend80s)
    4. Bubble Anak
    5. Gelembung Induk
  • stopPropagation() akan menghentikan aliran

gunakan aliran Capture

Demo

Hasil:

  1. Capture Induk
  2. Target Bubble 1

    (Karena Capture dan Bubble of Target akan memicu dalam urutan mereka terdaftar, jadi Bubble event memicu sebelum acara Capture)

  3. Capture Target

  4. Target Bubble 2
  5. Gelembung Induk

var parent = document.getElementById('parent'),
target = document.getElementById('target');

target.addEventListener('click', function (e) { 
console.log('Target Bubble 1');
// e.stopPropagation();
}, false);

target.addEventListener('click', function (e) { 
console.log('Target Capture');
// e.stopPropagation();
}, true);

target.addEventListener('click', function (e) { 
console.log('Target Bubble 2');
// e.stopPropagation();
}, false);

parent.addEventListener('click', function (e) { 
console.log('Parent Capture');
// e.stopPropagation();
}, true);

parent.addEventListener('click', function (e) { 
console.log('Parent Bubble');
// e.stopPropagation();
}, false);
<div id="parent">
    <button id="target" style="padding: 1em 0.8em;">
        Trigger event
    </button>
</div>

Steely Wing
sumber
1
Ada kesalahan dalam contoh: Anda mendeklarasikan acara anak dalam urutan: 1. tangkapan anak 2. gelembung anak Itu penting! Hanya karena jika Anak akan menjadi target acara, pendengar akan dipanggil dalam urutan yang sama. Lihat catatan di MDN: saat elemen menjadi target parameter 'useCapture' acara tidak menjadi masalah. ( developer.mozilla.org/en-US/docs/Web/API/EventTarget/… )
bam
1
Catatan : Untuk pendengar acara yang dilampirkan ke target acara, acara tersebut berada dalam fase target, bukan fase menangkap dan menggelegak. Events in the target phase will trigger all listeners on an element in the order they were registered, regardless of the useCapture parameter.Dari developer.mozilla.org/en-US/docs/Web/API/EventTarget/… . Jadi tidak ada fase "Children Capture" dan "Children Bubble".
legend80s
Dan itu menjelaskan mengapa menjalankan contoh menghasilkan "Anak-anak gelembung 1" sebelum "Anak-anak menangkap", ketika diagram menunjukkan bahwa "menangkap" harus selalu terjadi terlebih dahulu untuk setiap elemen!
Gershom
18

Ketika Anda mengatakan useCapture = true, Event mengeksekusi atas ke bawah pada fase penangkapan ketika false itu melakukan bubble bottom to top.

sushil bharwani
sumber
11

Ini semua tentang model acara: http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-flow Anda dapat menangkap acara dalam fase menggelegak atau dalam fase menangkap. Pilihanmu.
Lihatlah http://www.quirksmode.org/js/events_order.html - Anda akan menemukannya sangat berguna.

NilColor
sumber
1
tautan ke w3 sama atau bahkan kurang berguna daripada pencarian google. Saya tidak mengerti apa-apa di sana.
Muhammad Umer
3
Ya, tautan w3 itu hanya kumpulan kata-kata yang sangat banyak, tetapi sebaliknya, tautan kedua ke situs quirksmode ini menjelaskan topik dengan sangat baik dan singkat.
Stano
11

Contoh kode:

<div id="div1" style="background:#9595FF">
  Outer Div<br />
  <div id="div2" style="background:#FFFFFF">
    Inner Div
  </div>
</div>

Kode Javascript:

d1 = document.getElementById("div1");
d2 = document.getElementById("div2");

jika keduanya disetel ke false

d1.addEventListener('click',function(){alert("Div 1")},false);
d2.addEventListener('click',function(){alert("Div 2")},false);

Menjalankan: Onclicking Inner Div, peringatan ditampilkan sebagai: Div 2> Div 1

Di sini skrip dieksekusi dari elemen dalam: Gelembung Peristiwa (useCapture telah disetel ke false)

div 1 disetel ke true dan div 2 disetel ke false

d1.addEventListener('click',function(){alert("Div 1")},true);
d2.addEventListener('click',function(){alert("Div 2")},false);

Menjalankan: Onclicking Inner Div, peringatan ditampilkan sebagai: Div 1> Div 2

Di sini skrip dieksekusi dari leluhur / elemen luar: Pengambilan Acara (useCapture telah disetel ke true)

div 1 disetel ke false dan div 2 disetel ke true

d1.addEventListener('click',function(){alert("Div 1")},false);
d2.addEventListener('click',function(){alert("Div 2")},true);

Menjalankan: Onclicking Inner Div, peringatan ditampilkan sebagai: Div 2> Div 1

Di sini skrip dieksekusi dari elemen dalam: Gelembung Peristiwa (useCapture telah disetel ke false)

div 1 disetel ke true dan div 2 disetel ke true

d1.addEventListener('click',function(){alert("Div 1")},true);
d2.addEventListener('click',function(){alert("Div 2")},true);

Menjalankan: Onclicking Inner Div, peringatan ditampilkan sebagai: Div 1> Div 2

Di sini skrip dieksekusi dari elemen leluhur / luar: Pengambilan Acara sejak useCapture telah disetel ke true

shadowBot
sumber
1
Apa arti dari chevron "lebih besar dari" dalam konteks ini?
2540625
9

Ringkasan:

The DOMspesifikasi yang dijelaskan dalam:

https://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/events.html#Events-phases

bekerja dengan cara berikut:

Suatu peristiwa dikirim mengikuti jalur dari root ( document) dari pohon ke node target . Node target adalah HTMLelemen yang paling dalam , yaitu event.target. Acara pengiriman (juga disebut propagasi acara) terjadi dalam tiga fase dan urutan berikut:

  1. Fase penangkapan: peristiwa dikirim ke nenek moyang target dari akar pohon ( document) ke induk langsung dari simpul target.
  2. Fase target: acara dikirim ke node target. Fase target selalu berada pada htmlelemen terdalam tempat acara tersebut diberhentikan.
  3. Fase menggelegak: peristiwa dikirim ke nenek moyang target dari induk langsung dari simpul target ke akar pohon.

Gelembung acara, penangkapan acara, target acara

Contoh:

// bubbling handlers, third argument (useCapture) false (default)
document.getElementById('outerBubble').addEventListener('click', () => {
  console.log('outerBubble');
}, false)

document.getElementById('innerBubble').addEventListener('click', () => {
  console.log('innerBubble');
}, false)


// capturing handlers, third argument (useCapture)  true
document.getElementById('outerCapture').addEventListener('click', () => {
  console.log('outerCapture');
}, true)

document.getElementById('innerCapture').addEventListener('click', () => {
  console.log('innerCapture');
}, true)
div:hover{
  color: red;
  cursor: pointer;
}
<!-- event bubbling -->
<div id="outerBubble">
  <div id="innerBubble">click me to see Bubbling</div>
</div>


<!-- event capturing -->
<div id="outerCapture">
  <div id="innerCapture">click me to see Capturing</div>
</div>

Contoh di atas benar-benar menggambarkan perbedaan antara bubbling acara dan penangkapan acara. Saat menambahkan acara dengan pendengaraddEventListener , ada elemen ketiga yang disebut useCapture. Ini booleanyang ketika diatur untuk truememungkinkan pendengar acara untuk menggunakan menangkap acara, bukan menggelegak acara.

Dalam contoh kita ketika kita mengatur argumen useCapture untuk falsekita melihat bahwa peristiwa itu terjadi. Pertama acara di fase target dipecat (log innerBubble), dan kemudian melalui acara menggelegak acara di elemen induk dipecat (log outerBubble).

Ketika kita mengatur argumen useCapture untuk truekita melihat bahwa peristiwa di luar <div>dipecat terlebih dahulu. Ini karena acara sekarang dipecat dalam fase menangkap dan bukan fase menggelegak.

Willem van der Veen
sumber
7

Diberikan tiga fase perjalanan acara :

  1. The capture fase : acara ini dikirim ke nenek moyang target dari akar pohon untuk induk langsung dari node target.
  2. The fase Target : acara ini dikirim ke node target.
  3. The fase menggelegak : acara ini dikirim ke nenek moyang target dari induk langsung dari node target ke akar pohon.

useCapturemenunjukkan fase perjalanan acara akan berada pada:

Jika true, useCapture menunjukkan bahwa pengguna ingin menambahkan pendengar acara hanya untuk fase penangkapan, yaitu pendengar acara ini tidak akan dipicu selama fase target dan gelembung. Jika false, pendengar acara hanya akan dipicu selama fase target dan gelembung

Sumber adalah sama dengan jawaban terbaik kedua: https://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/events.html#Events-phases

Aurima
sumber
2

Urutan definisi hanya penting jika item berada pada level yang sama. Jika Anda membalik urutan definisi dalam kode Anda, Anda akan mendapatkan hasil yang sama.

Namun, jika Anda membalikkan pengaturan useCapture pada dua penangan peristiwa, penangan peristiwa anak merespons sebelum orang tua. Alasan untuk ini adalah bahwa pengendali event anak sekarang akan dipicu pada fase penangkapan yang sebelum fase gelembung di mana pengendali event induk akan dipicu.

Jika Anda mengatur useCapture menjadi true untuk kedua penangan acara - terlepas dari urutan definisi - penangan peristiwa induk akan dipicu terlebih dahulu karena itu datang sebelum anak dalam fase menangkap.

Sebaliknya, jika Anda menetapkan useCapture ke false untuk kedua penangan acara - lagi-lagi terlepas dari urutan definisi - penangan peristiwa anak akan dipicu terlebih dahulu karena itu datang sebelum induk dalam fase menggelegak.

WXB13
sumber