DOM da Event Bubbling mexanizmi, event.target vs event.currentTarget, stopPropagation(), Event Delegation naqshi va dinamik elementlar bilan samarali ishlash.
Bu bob — DOM hodisalarining eng chuqur va kuchli mavzusi. Chapter 33'da event.target haqida qisqacha eslatib o'tgan edik — endi buning ortida turgan mexanizmni to'liq ochib beramiz.
Event Bubbling — hodisa element ustida yuz berganda, u faqat o'sha elementda emas, balki uning barcha ota-elementlarida ham (tepaga qarab, "ko'pikdek ko'tarilib") ketma-ket ishga tushishi.
🫧 Bubbling — bu suv ostida ko'pik ko'tarilishiga o'xshaydi: ko'pik (event) eng pastki nuqtada (bosilgan elementda) paydo bo'ladi, keyin sirtga qarab (ota-elementlarga) ko'tarilib boradi, har bir "qatlam"dan o'tib ketadi.
index.htmlHTML<div id="outer">Tashqi<div id="middle">O'rta<button id="inner">Bosing</button></div></div>
script.jsJavaScriptdocument.getElementById("outer").addEventListener("click", () => {console.log("Outer bosildi");});document.getElementById("middle").addEventListener("click", () => {console.log("Middle bosildi");});document.getElementById("inner").addEventListener("click", () => {console.log("Inner (button) bosildi");});
Agar foydalanuvchi faqat tugmani (inner) bossa, natija:
code.textTEXTInner (button) bosildiMiddle bosildiOuter bosildi
code.textTEXTouter ←──┐│ │ 3-qadammiddle ←──┤│ │ 2-qadaminner ←──┘ 1-qadam (bosilgan joy)(button)
Garchi foydalanuvchi faqat inner tugmasini bossa ham, hodisa avtomatik ravishda uning barcha ota-elementlariga ham "ko'tariladi" va ularning har birida o'rnatilgan listener'lar ham ishga tushadi — bu standart DOM xatti-harakati.
🔥 Important
Aksariyat hodisalar (click, mouseover va h.k.) bubbling qiladi. Lekin ba'zi hodisalar (masalan, focus, blur) — bubbling qilmaydi.
Bubbling jarayonida, ikkita muhim propertyni farqlash kerak:
event.target — hodisa aslida qayerda boshlangan (foydalanuvchi qayerni bosgan).event.currentTarget — hodisa hozir qaysi listenerda ishlayotgan (this bilan bir xil).script.jsJavaScriptdocument.getElementById("outer").addEventListener("click", function (event) {console.log("target: " + event.target.id);console.log("currentTarget: " + event.currentTarget.id);});
Agar foydalanuvchi inner tugmasini bossa:
code.textTEXTtarget: innercurrentTarget: outer
event.target — har doim, listener qaysi elementda o'rnatilganidan qat'i nazar, haqiqiy bosilgan elementni ko'rsatadi. event.currentTarget esa — listener hozir ishlayotgan elementni (bu holatda outer) ko'rsatadi.
💡 Key Idea
Bu farq — keyingi bo'limda ko'rib chiqiladigan Event Delegation naqshining asosini tashkil qiladi.
event.stopPropagation() — hodisaning yuqoriga "ko'tarilishini" (bubbling'ni) to'xtatadi.
script.jsJavaScriptdocument.getElementById("inner").addEventListener("click", function (event) {event.stopPropagation();console.log("Faqat inner ishladi");});document.getElementById("outer").addEventListener("click", function () {console.log("Bu hech qachon chiqmaydi (agar inner bosilsa)");});
⚠️ Common Mistake
stopPropagation()ni haddan tashqari ko'p ishlatish — dasturni "bashorat qilib bo'lmaydigan" holga keltiradi, chunki boshqa qismlarda (masalan, analytics kuzatuvi uchun ota-elementga qo'yilgan umumiy listener'da) hodisa kutilganidek ishlamay qoladi. Bu metod faqat chindan ham zarur bo'lgandagina ishlatilishi tavsiya etiladi.
Event Delegation — har bir bola elementga alohida-alohida listener qo'shish o'rniga, bitta umumiy listenerni ota-elementga qo'yib, event.target orqali qaysi bola element bosilganini aniqlash texnikasi. Bu — Bubbling mexanizmining eng kuchli amaliy qo'llanilishi.
Aytaylik, sizda 100 ta <li> elementi bor va har biriga click listener kerak. Buni ikki xil usulda amalga oshirish mumkin.
script.jsJavaScriptlet items = document.querySelectorAll("li");items.forEach(item => {item.addEventListener("click", function () {console.log("Bosildi: " + this.textContent);});});// 100 ta alohida listener — xotirada ko'p joy egallaydi
Muammo: Bu — 100 ta alohida listener yaratadi. Bundan tashqari, agar keyinchalik yangi <li> element dinamik qo'shilsa (masalan, JavaScript orqali), unga listener avtomatik qo'shilmaydi — uni alohida qo'shish kerak bo'ladi.
script.jsJavaScriptlet list = document.getElementById("myList");list.addEventListener("click", function (event) {if (event.target.tagName === "LI") {console.log("Bosildi: " + event.target.textContent);}});
Bu yerda — bitta yagona listener, <ul> elementining o'zida. Bubbling tufayli, har qanday <li> bosilganda, hodisa <ul>gacha "ko'tariladi", va biz event.target orqali aynan qaysi <li> bosilganini aniqlaymiz.
code.textTEXTYomon usul: Yaxshi usul (Delegation):<ul> <ul> ← BITTA listener shu yerda├─ <li> [listener 1]├─ <li> [listener 2] ├─ <li>├─ ... ├─ <li>└─ <li> [listener 100] └─ <li> (hech biriga listener yo'q)
<li> qo'shilsa, listener uni ham "avtomatik qamrab oladi", chunki listener ota-elementda, va yangi bola ham bubbling qiladi.script.jsJavaScriptlet list = document.getElementById("myList");list.addEventListener("click", function (event) {if (event.target.tagName === "LI") {event.target.classList.toggle("done");}});// Keyinroq dinamik ravishda yangi element qo'shilsa:let newItem = document.createElement("li");newItem.textContent = "Yangi vazifa";list.appendChild(newItem);// newItem ustiga bosilganda ham, YUQORIDAGI listener ishlaydi —// chunki unga alohida listener qo'shish shart emas edi!
🔥 Important
Event Delegation — zamonaviy veb-dasturlashda (ayniqsa, ro'yxatlar, jadvallar, dinamik kontentda) juda keng qo'llaniladigan, muhim naqsh hisoblanadi.
Task:
Ichma-ich joylashgan ikkita <div> yarating (outer va inner). Ikkalasiga ham click listener qo'shib, innerni bosganda ikkala listener ham ishga tushishini (bubbling tufayli) tekshiring.
Required Concepts:
Task:
inner elementga stopPropagation() qo'shib, outerning listeneri endi ishga tushmasligini tekshiring.
Required Concepts:
stopPropagation()event.stopPropagation()ni innerning listeneri ichiga yozing.Task:
<ul id="todoList"> yarating, ichida bir nechta <li> (har birida matn va "O'chirish" tugmasi). Event Delegation yordamida, todoListning o'ziga bitta listener qo'ying: agar bosilgan element "O'chirish" tugmasi bo'lsa (event.target.classList.contains("delete-btn")), uning ota-<li>sini butunlay o'chiring (event.target.closest("li").remove()).
Required Concepts:
closest()remove()closest("li") — eng yaqin <li> ota-elementini topadi.index.htmlHTML<div id="a"><div id="b"><div id="c"></div></div></div>
script.jsJavaScriptdocument.getElementById("a").addEventListener("click", () => console.log("A"));document.getElementById("b").addEventListener("click", () => console.log("B"));document.getElementById("c").addEventListener("click", () => console.log("C"));document.getElementById("c").click(); // dasturiy ravishda bosish
🧠 Think first! Javobni ko'rishdan oldin kamida 30 soniya o'ylang.
<details> <summary>Answer</summary> C B AWhy?
c.click() — c elementida click hodisasini dasturiy ravishda ishga tushiradi. Bubbling tufayli, bu hodisa avval cning o'zida ("C"), keyin bda ("B"), keyin ada ("A") ishga tushadi — eng ichkaridan tashqariga qarab.
Quyidagi kodda muammo bor — dasturchi ro'yxatga dinamik qo'shilgan elementlar uchun ham click ishlashini kutmoqda, lekin ishlamayapti:
script.jsJavaScriptlet items = document.querySelectorAll("#list li");items.forEach(item => {item.addEventListener("click", () => {console.log("Bosildi: " + item.textContent);});});// Keyinroq:let newItem = document.createElement("li");newItem.textContent = "Yangi element";document.getElementById("list").appendChild(newItem);// newItem bosilganda hech narsa chiqmaydi
Your Task:
Yechim — Event Delegation:
</details>script.jsJavaScriptlet list = document.getElementById("list");list.addEventListener("click", function (event) {if (event.target.tagName === "LI") {console.log("Bosildi: " + event.target.textContent);}});// Endi yangi qo'shilgan elementlar ham AVTOMATIK ishlaydi:let newItem = document.createElement("li");newItem.textContent = "Yangi element";list.appendChild(newItem);
event.target — haqiqiy bosilgan element, event.currentTarget — listener joylashgan element.stopPropagation() — bubbling jarayonini to'xtatadi.event.target.tagName yoki classList.contains() — delegation ichida "qaysi element bosilgani"ni aniqlash uchun ishlatiladi.stopPropagation()ni ehtiyotkorlik bilan, faqat zarur bo'lgandagina ishlating.script.jsJavaScript// Bubblingparent.addEventListener("click", (e) => {console.log(e.target); // aniq bosilgan elementconsole.log(e.currentTarget); // listener joylashgan element});e.stopPropagation(); // bubbling'ni to'xtatish// Event Delegationlist.addEventListener("click", (e) => {if (e.target.matches("li")) {console.log(e.target.textContent);}});
Mavzu bo‘yicha tushunchalaringizni interaktiv test orqali sinovdan o‘tkazing va natijalarni bilib oling.
Darslikda o‘rganilgan qoidalarga asosan real kod yozing, testlardan o‘tkazing va yechimlarni mustahkamlang.
Test Sinovi
Hali topshirilmagan (kamida 75% kerak)
Amaliy Masalalar
0 / 3 ta yechildi (kamida 75% kerak)
Dars sifati va mazmunini yaxshilash uchun o‘z haqqoniy bahoingizni qoldiring.
Mavzuni to‘liq o‘zlashtirish uchun test sinovi, amaliy kodlash va bog‘liq darslar
O‘z bilimingizni interaktiv test savollari orqali tekshiring va darhol xatolarni tahlil qiling.
Nazariyani real kod yozish bilan mustahkamlang, avtomatik testlardan o‘ting va XP to‘plang.
Kurs bo‘yicha keyingi va bog‘liq mavzular: