Event capturing
Event capturing bubbling'ning aksi ekani, addEventListener'ning uchinchi argumenti orqali capturing/bubbling tanlanishi, to'liq uch bosqichli oqim, capturing nima uchun kerakligi (stopPropagation'dan himoya, modal/dropdown), va brauzer bu ikkovini bitta yo'l massivi orqali qanday amalga oshirishi.
57-dars
Event capturing
Event capturing — bubbling'ning aksi: hodisa documentdan boshlab, DOM daraxti bo'ylab yuqoridan pastga, aynan bosilgan elementga (target) qarab "tushib boradi". Bu — oldingi mavzuda ko'rgan capturing phase — u har doim sodir bo'ladi, lekin odatda ko'rinmaydi, chunki addEventListener standart holatda faqat bubbling'ni "tinglaydi".
<div id="outer">
<div id="inner">
<button id="btn">Bos</button>
</div>
</div>
document.getElementById('outer').addEventListener('click', () => console.log('outer capturing'), true);
document.getElementById('inner').addEventListener('click', () => console.log('inner capturing'), true);
document.getElementById('btn').addEventListener('click', () => console.log('btn capturing'), true);
addEventListenerning uchinchi argumenti — true (yoki { capture: true }) — aynan shu: "Bu listener'ni bubbling paytida emas, capturing paytida ishga tushir" degan buyruq.
Natija:
outer capturing
inner capturing
btn capturing
Diqqat qiling — tartib teskari: eng tashqi elementdan boshlanib, eng ichkariga qarab boradi. Bubbling'da esa aksincha edi (btn → inner → outer).
1. To'liq uch bosqichni birga ko'rish
Agar bir elementga ham capturing, ham bubbling listener qo'ysak:
['outer', 'inner', 'btn'].forEach(id => {
document.getElementById(id).addEventListener('click', () => console.log(id + ' CAPTURE'), true);
document.getElementById(id).addEventListener('click', () => console.log(id + ' BUBBLE'), false);
});
btnni bossangiz, natija aniq shu tartibda chiqadi:
outer CAPTURE
inner CAPTURE
btn CAPTURE
btn BUBBLE
inner BUBBLE
outer BUBBLE
Bu — Event bubbling mavzusida ko'rgan uch bosqichning to'liq, real manzarasi:
document → html → body → outer → inner → btn (CAPTURING — yuqoridan pastga)
btn (TARGET — capture va bubble ikkovi ham shu yerda)
btn → inner → outer → body → html → document (BUBBLING — pastdan yuqoriga)
Har bir hodisa — doim shu uch bosqichdan o'tadi, farqi shundaki, siz addEventListenerning uchinchi argumenti orqali qaysi bosqichda "tinglashni" tanlaysiz.
2. Nega bu ikki bosqich umuman kerak — capturing nima uchun mavjud?
Oldingi mavzuda aytilganidek — bu tarixiy kelib chiqish (Netscape vs Microsoft), lekin amaliy foydasi ham bor: capturing sizga "ichkaridagi elementning o'ziga yetib borishidan oldin, uni ushlab qolish" imkonini beradi.
Eng aniq misol — modal oyna yoki dropdown'ni yopish:
document.addEventListener('click', (event) => {
if (!dropdown.contains(event.target)) {
dropdown.style.display = 'none';
}
}, true); // capturing — sahifadagi HAR QANDAY bosishni birinchi bo'lib "ko'radi"
Bu yerda capturing ishlatilishining sababi: agar ichkaridagi biror tugma o'zining click listener'ida stopPropagation() chaqirsa (bubbling'ni to'xtatsa), oddiy bubbling listener hech qachon ishga tushmaydi. Lekin capturing listener — bubbling boshlanishidan oldin, yo'lning eng boshida allaqachon ishlagan bo'ladi, shuning uchun u stopPropagation()dan himoyalangan.
3. Brauzer darajasida
V8/Blink darajasida, capturing va bubbling — bitta yagona algoritmning ikki yarmi, alohida mexanizmlar emas. Hodisa yuz berganda, Blink:
targetdandocumentgacha bo'lgan to'liq yo'lni (path) DOM daraxti bo'ylab avvaldan hisoblab, massiv sifatida tuzadi:[document, html, body, outer, inner, btn]- Shu massivni boshidan oxirigacha yurib chiqadi (capturing) — har bir node'da, agar
capture: truebilan ro'yxatga olingan listener bo'lsa, chaqiradi targetga yetgach — o'sha yerdagi barcha listener'larni (capture ham, bubble ham, qo'shilgan tartibda) chaqiradi- Keyin massivni teskari tartibda (oxiridan boshigacha) yurib chiqadi (bubbling) — har bir node'da
capture: false(standart) listener'larni chaqiradi
Ya'ni bu — oldingi mavzularda ko'rgan oddiy massiv bo'ylab ikki marta (oldinga va orqaga) yurish kabi sodda tuzilma, faqat brauzer C++ darajasida buni juda tez bajaradi. Hech qanday "sehr" yo'q — bitta yo'l massivi, ikki yo'nalishda aylanish, har bir bekatda tegishli listener ro'yxatini tekshirish.
4. stopPropagation() — capturing bosqichida ham ishlaydi
document.getElementById('inner').addEventListener('click', (event) => {
event.stopPropagation();
console.log("inner CAPTURE — to'xtatildi");
}, true);
Agar stopPropagation() capturing paytida chaqirilsa — endi hodisa innerdan pastga (ya'ni btnga) hech qachon yetib bormaydi, target phase ham, bubbling phase ham umuman ishga tushmaydi. Bu — capturing'ning yana bir kuchli tomoni: pastdagi hech narsa hodisani ko'ra olmaydi, chunki yo'l boshidayoq to'xtatilgan.
5. Qachon capturing, qachon bubbling ishlatiladi — amaliy qoida
| Holat | Qaysi bosqich |
|---|---|
| Oddiy tugma, forma, click handler | Bubbling (standart, 99% holat) |
| Event delegation (bitta ota-elementga umumiy listener) | Bubbling |
| Modal/dropdown tashqarisiga bosishni aniqlash | Capturing |
Ichkaridagi kodning stopPropagation()idan "himoyalanish" kerak bo'lganda |
Capturing |
| Sahifada global "log qilish" yoki analytics (har bir bosishni, hech narsa to'xtatmasdan, birinchi bo'lib ushlash) | Capturing |
Amaliyotda, dasturchilarning ko'pchiligi deyarli har doim bubblingdan foydalanadi — capturing kamdan-kam, faqat yuqoridagi kabi maxsus holatlarda kerak bo'ladi.
Xulosa
Event capturing — hodisaning documentdan targetgacha yuqoridan pastga "tushish" bosqichi, bubbling bilan bir xil yo'l massividan, lekin teskari yo'nalishda foydalanadi, va u sizga ichkaridagi elementga yetib borishidan oldin hodisani ushlab qolish imkonini beradi.