Mundarija (35)
- Bu darsda
- 1. Nega bu kerak?
- 2. Yaratish: createElement
- 2.1 Uch qadam
- 2.2 Teg nomi — oddiy satr
- 3. Joylash: to'rt yo'nalish
- 3.1 Ichiga va yoniga
- 3.2 Bir nechta narsa va matn
- 3.3 Eski usullar: appendChild va insertBefore
- 4. Mavjud elementni ko'chirish
- 5. Almashtirish va o'chirish
- 6. insertAdjacentHTML: HTML satrni aniq joyga
- 6.1 To'rt pozitsiya
- 6.2 Lekin u ham HTML o'qiydi
- 7. cloneNode — nusxa olish
- 8. Massivdan ro'yxat chizish
- 8.1 Ma'lumot → elementlar
- 8.2 Qo'shish va o'chirish — jonli
- 8.3 Ko'p element — keyingi qadam
- 9. Jonli hudud: oldindan bo'lsin
- 10. DevTools: DOM'ni kim o'zgartirdi?
- 11. Ko'p uchraydigan xatolar
- 11.1 Teg nomini burchak qavs bilan yozish
- 11.2 appendChild ga satr berish
- 11.3 Bitta elementni sikl ichida qayta-qayta qo'shish
- 11.4 Yaratib, qo'shishni unutish
- 11.5 Nusxadagi takroriy id
- 12. Mashqlar
- 1-mashq (oson): Aksiya bloki
- 2-mashq (o'rta): Bronlar jadvali
- 3-mashq (qiyin): Taomni menyudan savatga
- 4-mashq: Portfolio qadami — kartalarga texnologiya teglari
- 13. Real ishda
- Xulosa
- Manbalar
JavaScript'da element yaratish: createElement, append, remove va cloneNode
Qisqacha: Yangi element uch qadamda qo'shiladi:
document.createElement("li")bilan yaratasiz,textContent,classList,datasetbilan sozlaysiz,appendbilan sahifaga qo'yasiz. Joyniappend/prepend(ichiga, oxiri/boshiga) vabefore/after(yoniga) tanlaydi. Elementremove()bilan o'chadi,replaceWith()bilan almashadi,cloneNode(true)bilan nusxalanadi. Mavjud elementniappendqilsangiz — u nusxalanmaydi, ko'chadi.
Bu darsda
createElementbilan element yaratib, uni xavfsiz to'ldira olasiz.append,prepend,before,afterbilan elementni kerakli joyga qo'ya olasiz.replaceWithvaremovebilan elementni almashtirasiz va o'chirasiz.insertAdjacentHTMLvacloneNodeqachon qulay va qachon xavfli ekanini bilasiz.- Massivdagi ma'lumotdan sahifada ro'yxat chiza olasiz.
Oldin bilishingiz kerak: classList va stillarni JS'dan boshqarish, Kontentni o'zgartirish va XSS xavfi, Massiv bo'ylab yurish, Obyekt: kalit-qiymat juftliklari.
1. Nega bu kerak?
Hozirgacha sahifada bor elementlarni o'zgartirdik: matnini, atributini, class'ini. Lekin ko'pincha element umuman yo'q bo'ladi va uni yaratish kerak:
- Mehmon taomni savatga qo'shdi — savat ro'yxatida yangi qator paydo bo'lishi kerak.
- Serverdan bugungi izohlar keldi — har biri uchun
likerak. - Mehmon bronni bekor qildi — qator o'chishi kerak.
Massiv bo'ylab yurish darsida va'da qilgan edik: "DOM darslarida har element uchun sahifada yangi qator yaratamiz". O'tgan darslardan birida — Kontentni o'zgartirish — esa innerHTML += ning tuzog'ini ko'rdik: u hamma elementni qayta yaratadi, unga begona ma'lumot tushsa — XSS. Bugun ikkala masalaning to'g'ri yechimini o'rganamiz.
Hayotdan o'xshatish: oshxona va zal. Oshpaz Rustam aka taomni oshxonada tayyorlaydi — bu createElement. Taom tayyor, lekin mehmon uni hali ko'rmaydi. Unga ziravor sepiladi, likopchaga solinadi — bu textContent, classList. Faqat Otabek uni zalga olib chiqib, aniq stolga qo'ygandagina mehmon ko'radi — bu append. Stoldan olib ketish — remove.
2. Yaratish: createElement
2.1 Uch qadam
<ul id="menyu">
<li class="taom-karta">Osh</li>
</ul>
<script>
const menyu = document.querySelector("#menyu");
const manti = document.createElement("li");
console.log(manti, manti.isConnected);
manti.textContent = "Manti";
manti.classList.add("taom-karta", "yangi");
manti.dataset.narx = 30000;
menyu.append(manti);
console.log(manti.isConnected, menyu.children.length);
console.log(manti);
</script>Konsolda:
<li></li> false
true 2
<li class="taom-karta yangi" data-narx="30000">Manti</li>Qadamma-qadam:
document.createElement("li")— yangi, bo'shliyaratdi. U xotirada:isConnected—false, ekranda yo'q.- Sozlash — o'tgan darslardagi hamma asbob:
textContent(Kontentni o'zgartirish),classList(classListva stillar),dataset(Atributlar vadataset). menyu.append(manti)— menyuning oxiriga qo'ydi. EndiisConnected—true, ekranda ikkinchi qator.
isConnected — "element hozir sahifadami?" degan savolga true yoki false javob beradigan xususiyat. U Kontentni o'zgartirish darsidan tanish.
Tartibga e'tibor bering: avval sozlash, keyin qo'shish. Teskarisi ham ishlaydi. Lekin bu tartib tozaroq: element sahifaga to'liq tayyor holda chiqadi, kodni o'qigan odam ham "yasash" va "qo'yish"ni alohida ko'radi.
Va eng muhimi: matn textContent bilan qo'yildi. Taom nomi serverdan kelsa ham, XSS bo'lmaydi — u har doim matn.
2.2 Teg nomi — oddiy satr
createElement ga teg nomi qavssiz beriladi: "li", "article", "button". Katta-kichik harf muhim emas — HTML'da createElement("LI") ham li yaratadi. Natija qaysi "oila"dan ekanini DOM daraxti darsida ko'rgansiz: createElement("li") — HTMLLIElement.
Noma'lum nom ham xato bermaydi: createElement("taom") — HTMLUnknownElement yaratadi. U sahifada turadi, lekin hech qanday ma'nosi yo'q. Validator uni HTML'da xato derdi, JavaScript esa jim qoladi. Teg nomini to'g'ri yozganingizni tekshiring.
Tekshirib ko'ring: Kod
const li = document.createElement("li"); li.textContent = "Choy";bilan tugadi. Sahifada "Choy" ko'rinadimi?
Javob
Yo'q. Element yaratildi va to'ldirildi, lekin hech qayerga qo'shilmadi — u xotirada "osilib" turibdi (isConnected — false). Oshxonada tayyor turgan, lekin zalga chiqarilmagan taom. append qatori yetishmayapti.
3. Joylash: to'rt yo'nalish
3.1 Ichiga va yoniga
Yaratilgan elementni qayerga qo'yish — to'rtta metod hal qiladi. Ikkitasi elementning ichiga, ikkitasi yoniga:
<ul id="menyu"><li>Manti</li></ul>
<script>
const menyu = document.querySelector("#menyu");
const oxiri = document.createElement("li");
oxiri.textContent = "Ko'k choy";
menyu.append(oxiri);
const boshi = document.createElement("li");
boshi.textContent = "Osh";
menyu.prepend(boshi);
const sarlavha = document.createElement("h2");
sarlavha.textContent = "Bugungi menyu";
menyu.before(sarlavha);
const izoh = document.createElement("p");
izoh.textContent = "Narxlar so'mda.";
menyu.after(izoh);
console.log(menyu.textContent);
console.log(document.body.children);
</script>Konsolda:
OshMantiKo'k choy
HTMLCollection(4) [h2, ul#menyu, p, script]| Metod | Qayerga | Ma'nosi |
|---|---|---|
el.prepend(x) |
el ichiga, boshiga |
birinchi bola |
el.append(x) |
el ichiga, oxiriga |
oxirgi bola |
el.before(x) |
el dan oldin, tashqarida |
oldingi aka-uka |
el.after(x) |
el dan keyin, tashqarida |
keyingi aka-uka |
Diagrammada to'rtala joy — ul atrofida, yuqoridan pastga:
flowchart TD
B["before: ul dan oldin"]
subgraph UL["ul#menyu"]
direction TB
P["prepend: ichida, boshida"]
M["mavjud li"]
A["append: ichida, oxirida"]
end
F["after: ul dan keyin"]
B --> UL --> F
P --> M --> AOta-bola va aka-uka atamalari — DOM daraxti darsidan. Natijadagi script ham body ning bolasi — u ham DOM'da.
3.2 Bir nechta narsa va matn
Bu metodlar bir nechta argument oladi. Argument satr bo'lsa — u matn tuguni bo'lib qo'shiladi, HTML emas:
<p id="savat">Savatda:</p>
<script>
const savat = document.querySelector("#savat");
const soni = document.createElement("b");
soni.textContent = "3 ta";
savat.append(" ", soni, " taom. ", "<i>tekin</i>");
console.log(savat.childNodes.length);
console.log(savat.innerHTML);
</script>Konsolda:
5
Savatda: <b>3 ta</b> taom. <i>tekin</i>Bitta chaqiruv to'rtta narsa qo'shdi: uchta matn va bitta element. Oxirgi satrdagi <i> kursivga aylanmadi — append satrni har doim matn deb biladi. Demak, append("…") ham textContent kabi xavfsiz.
3.3 Eski usullar: appendChild va insertBefore
Eski kodda bu metodlarni ko'p uchratasiz:
| Eski | Yangi | Farqi |
|---|---|---|
ota.appendChild(el) |
ota.append(el) |
Faqat bitta tugun, satr qabul qilmaydi; qo'shilgan tugunni qaytaradi |
ota.insertBefore(el, qoshni) |
qoshni.before(el) |
Otani ham, qo'shnini ham bilish kerak |
ota.removeChild(el) |
el.remove() |
Otani bilish kerak |
ota.replaceChild(yangi, eski) |
eski.replaceWith(yangi) |
Otani bilish kerak |
Yangi metodlar 2018-yildan beri hamma brauzerda ishlaydi (Baseline). Yangi kodda ularni ishlating. appendChild ga satr bersangiz, xato chiqadi — buni «Ko'p uchraydigan xatolar» bo'limida ko'ramiz.
Tekshirib ko'ring:
ulning ichida ikkitalibor. Ikkinchilidan keyin, lekinulichiga yangiliqo'shish uchun qaysi ikki usul bor?
Javob
ul.append(yangi) — ul ning oxiriga, ya'ni ikkinchi li dan keyin. Yoki ikkinchiLi.after(yangi) — ikkinchi li ning yoniga, u ham ul ichida. Natija bir xil. ul.after(yangi) esa li ni ul dan tashqariga qo'yardi — noto'g'ri HTML.
4. Mavjud elementni ko'chirish
Bitta element DOM'da faqat bitta joyda bo'la oladi. Sahifada turgan elementni append qilsangiz, u nusxalanmaydi — eski joyidan ko'chadi:
<h3>Menyu</h3>
<ul id="menyu"><li>Osh</li><li>Manti</li></ul>
<h3>Savat</h3>
<ul id="savat"></ul>
<script>
const manti = document.querySelector("#menyu li:last-child");
document.querySelector("#savat").append(manti);
console.log(document.querySelector("#menyu").children.length);
console.log(document.querySelector("#savat").children.length);
</script>Konsolda:
1
1Manti menyudan chiqib, savatga o'tdi. Bu ro'yxatni qayta tartiblashda qulay: elementni o'chirib, qaytadan yaratish shart emas — uni boshqa joyga append, before yoki after qilish kifoya. Element o'zining class'lari, atributlari va keyinroq o'rganadigan hodisa tinglovchilari bilan birga ko'chadi.
Bitta nozik fakt: ko'chirish aslida "olib tashlash + qo'yish". Shuning uchun ko'chayotgan <video> to'xtab qoladi, <iframe> qayta yuklanadi. Buni hal qiladigan yangi metod bor — moveBefore. U Chrome 133+ va Firefox 144+ da ishlaydi, Safari'da yo'q (web-features, 2026-yil oktabr) — hali Baseline emas. Hozircha bilib qo'ying, ishlatishga shoshilmang.
5. Almashtirish va o'chirish
<ul id="menyu">
<li id="osh">Osh</li>
<li id="manti">Manti</li>
<li id="kompot">Kompot</li>
</ul>
<script>
const manti = document.querySelector("#manti");
const lagmon = document.createElement("li");
lagmon.textContent = "Lag'mon";
manti.replaceWith(lagmon);
console.log(manti.isConnected);
const kompot = document.querySelector("#kompot");
kompot.remove();
kompot.remove();
console.log(document.querySelector("#menyu").children);
console.log(kompot, kompot.isConnected);
</script>Konsolda:
false
HTMLCollection(2) [li#osh, li]
<li id="kompot">Kompot</li> falseeski.replaceWith(yangi)— eski element o'rniga yangisini qo'yadi. Manti endi sahifada yo'q (false), uning joyida — Lag'mon. Bir nechta argument ham bersa bo'ladi:replaceWith(a, b, "matn").el.remove()— elementni DOM'dan olib tashlaydi. Ikkinchi marta chaqirilsa ham xato bermaydi.- O'chirilgan element yo'qolmaydi:
kompoto'zgaruvchisi uni hamon ushlab turibdi — barcha atributlari va matni bilan. Uni qaytadanappendqilsangiz, sahifaga qaytadi. O'zgaruvchi ham unutilgandagina brauzer uni xotiradan tozalaydi.
Uchinchi xususiyat amalda foydali: "Bekor qilish" (undo) tugmasi o'chirilgan qatorni saqlab turib, kerak bo'lsa qaytaradi.
Tekshirib ko'ring:
ulichidagi hammalini o'chirish kerak.for (const li of ul.children) li.remove();— nega bu ishonchsiz va qanday tuzatiladi?
Javob
children — jonli HTMLCollection (Elementlarni tanlash): har remove uni qisqartiradi va sikl elementlarni tashlab ketadi — yarmi qoladi. Tuzatish: statik ro'yxatni aylaning — for (const li of ul.querySelectorAll("li")). Yoki ichini butunlay tozalang: ul.textContent = "" (Kontentni o'zgartirish). Hamma bolani bir martada almashtirishning maxsus metodi ham bor — replaceChildren, uni Ko'p elementni samarali chizish darsida ko'ramiz.
6. insertAdjacentHTML: HTML satrni aniq joyga
6.1 To'rt pozitsiya
Ba'zan elementni bittalab yaratish o'rniga kichik HTML satr yozish qulayroq. Buning uchun insertAdjacentHTML(pozitsiya, satr) bor. Pozitsiyalar — yuqoridagi to'rt metodning eski nomlari:
| Pozitsiya | Qaysi metodga teng |
|---|---|
"beforebegin" |
before |
"afterbegin" |
prepend |
"beforeend" |
append |
"afterend" |
after |
<ul id="menyu"><li>Osh</li></ul>
<script>
const menyu = document.querySelector("#menyu");
const osh = menyu.firstElementChild;
menyu.insertAdjacentHTML("beforeend", "<li>Manti</li>");
menyu.insertAdjacentHTML("afterbegin", "<li>Ko'k choy</li>");
menyu.insertAdjacentHTML("beforebegin", "<h2>Menyu</h2>");
console.log(menyu.children.length, osh.isConnected);
</script>Konsolda:
3 trueKontentni o'zgartirish darsidagi innerHTML += bilan solishtiring: u yerda osh.isConnected false bo'lib qolgan edi — hamma element qayta yaratilgandi. insertAdjacentHTML esa mavjud elementlarga tegmaydi: faqat yangi qismni o'qib, kerakli joyga qo'shadi. Osh — o'sha-o'sha element.
6.2 Lekin u ham HTML o'qiydi
Nomidagi "HTML" so'zi ogohlantirish: insertAdjacentHTML satrni innerHTML kabi HTML deb o'qiydi. Unga begona ma'lumot tushsa — xuddi o'sha XSS (Kontentni o'zgartirish va XSS xavfi darsidagi «Hujumchi nigohi»). Qoida o'zgarmaydi: bu metodga faqat o'zingiz yozgan satr.
Uning ikki xavfsiz qarindoshi bor:
insertAdjacentText(pozitsiya, matn)— satrni matn sifatida qo'yadi.insertAdjacentElement(pozitsiya, element)— tayyor elementni qo'yadi.
Lekin ular kam ishlatiladi: append, before va boshqalar xuddi shu ishni qisqaroq qiladi.
7. cloneNode — nusxa olish
Bir xil tuzilishli ko'p karta kerak bo'lsa, bittasini nusxalash mumkin. cloneNode(true) — elementni butun ichi bilan, cloneNode() (yoki false) — faqat elementning o'zini, bolalarsiz:
<article id="karta" class="taom-karta" data-taom-raqami="17">
<h3>Osh</h3>
<p>35 000 so'm</p>
</article>
<script>
const karta = document.querySelector("#karta");
const yuza = karta.cloneNode();
const toliq = karta.cloneNode(true);
console.log(yuza.children.length, toliq.children.length);
console.log(toliq.id, toliq.dataset.taomRaqami, toliq.isConnected);
toliq.removeAttribute("id");
toliq.dataset.taomRaqami = 18;
toliq.querySelector("h3").textContent = "Manti";
toliq.querySelector("p").textContent = "30 000 so'm";
karta.after(toliq);
console.log(document.querySelectorAll(".taom-karta").length);
</script>Konsolda:
0 2
karta 17 false
2Nusxa xotirada tug'iladi (isConnected — false) va hamma atributni oladi: class, data-*, hatto id. Shuning uchun toliq.removeAttribute("id") — majburiy qadam. Bir sahifada ikki bir xil id — Elementlarni tanlash darsidagi tuzoq: getElementById faqat birinchisini topadi.
Yana bir fakt: addEventListener bilan qo'shilgan tinglovchilar nusxalanmaydi — Chrome'da tekshirdik. Nusxadagi tugma bosilganda hech narsa bo'lmaydi. Buni addEventListener asoslari darsida jonli oynada ko'rasiz.
Amalda kartalarni nusxalashning yanada qulay yo'li — <template> tegi. Uning ichidagi kontent sahifada ko'rinmaydi va faqat nusxalash uchun turadi. Uni Ko'p elementni samarali chizish darsida o'rganamiz.
8. Massivdan ro'yxat chizish
8.1 Ma'lumot → elementlar
Endi hammasini birlashtiramiz. Ma'lumot — obyektlar massivi (Obyekt va massiv darslari). Har obyektdan bitta element yasaymiz va ro'yxatga qo'shamiz:
<h2>Bugungi menyu</h2>
<ul id="menyu"></ul>
<script>
const taomlar = [
{ nomi: "Osh", narx: 35000 },
{ nomi: "Lag'mon", narx: 28000, achchiq: true },
{ nomi: "Manti", narx: 30000 },
{ nomi: "Ko'k choy", narx: 5000 },
];
function taomQatoriniYasa(taom) {
const li = document.createElement("li");
li.classList.add("taom-karta");
li.classList.toggle("achchiq", taom.achchiq === true);
const narx = document.createElement("span");
narx.classList.add("narx");
narx.textContent = `${taom.narx} so'm`;
li.append(`${taom.nomi} — `, narx);
return li;
}
const menyu = document.querySelector("#menyu");
for (const taom of taomlar) {
menyu.append(taomQatoriniYasa(taom));
}
console.log(menyu.children.length);
console.log(menyu.children[1]);
</script>Konsolda:
4
<li class="taom-karta achchiq">…</li>Ishni ikki funksiyaga bo'ldik:
taomQatoriniYasa(taom)— bitta obyektdan bitta tayyorliyasaydi va qaytaradi. U sahifaga tegmaydi — faqat element yasaydi. Nomi funksiya nomlash qoidasi bo'yicha: fe'l bilan.- Sikl — har taom uchun yasaydi va qo'shadi.
Bu bo'linish keyin juda qo'l keladi: yangi taom kelsa — menyu.append(taomQatoriniYasa(yangiTaom)). Qatorning ko'rinishini o'zgartirish kerak bo'lsa — faqat bitta funksiyaga tegasiz.
Ma'lumotda achchiq ba'zi taomlarda yo'q — taom.achchiq === true u yerda false beradi va toggle class qo'shmaydi (classList va stillar darsidagi toggle(nom, shart): shart true bo'lsa qo'shadi, false bo'lsa olib tashlaydi).
8.2 Qo'shish va o'chirish — jonli
Quyidagi oynada ikki tugma bor. Tugma bosilganda kod ishlashi uchun o'tgan darslardagi qolipni ishlatdik: tugma.addEventListener("click", () => { ... }) — "bosilganda shu funksiyani chaqir". Uni addEventListener asoslari darsida to'liq o'rganamiz.
Ko'k choy qo'shish ni bir necha marta bosing, keyin Oxirgisini o'chirish ni:
<ul id="savat">
<li>Osh</li>
</ul>
<p id="jami"></p>
<button type="button" id="qosh">Ko'k choy qo'shish</button>
<button type="button" id="ochir">Oxirgisini o'chirish</button>
<script>
const savat = document.querySelector("#savat");
const jami = document.querySelector("#jami");
function jaminiYangila() {
jami.textContent = `Savatda: ${savat.children.length} ta`;
console.log(jami.textContent);
}
document.querySelector("#qosh").addEventListener("click", () => {
const li = document.createElement("li");
li.textContent = "Ko'k choy";
savat.append(li);
jaminiYangila();
});
document.querySelector("#ochir").addEventListener("click", () => {
savat.lastElementChild?.remove();
jaminiYangila();
});
jaminiYangila();
</script>Konsolda:
Savatda: 1 taHar qo'shish yangi li yaratadi va son ortadi: Savatda: 2 ta, Savatda: 3 ta. O'chirish oxirgi qatorni oladi. Savat bo'shab qolganda ham xato chiqmaydi: lastElementChild — oxirgi bola element, bo'lmasa null (DOM bo'ylab harakatlanish darsida batafsil), ?. esa null da to'xtaydi (optional chaining).
8.3 Ko'p element — keyingi qadam
Yuqoridagi siklda har append — sahifaga alohida o'zgarish. To'rtta taom uchun bu sezilmaydi. 1 000 ta qator bo'lsa, ularni avval "vaqtinchalik qutiga" yig'ib, bir martada qo'shish tezroq — bu Ko'p elementni samarali chizish darsining mavzusi. Ma'lumot o'zgarganda butun ro'yxatni qaytadan chizish g'oyasi esa — state → render.
9. Jonli hudud: oldindan bo'lsin
Jonli hududlar darsida "nega tayyor xabar bilan birga qo'shish ishlamaydi" degan savol bor edi. Endi uni JavaScript tilida ko'ramiz:
// ❌ hudud xabari bilan birga yangi yaratildi — ekran o'quvchi jim
const xabar = document.createElement("p");
xabar.setAttribute("aria-live", "polite");
xabar.textContent = "Osh savatga qo'shildi";
document.body.append(xabar);
// ✅ hudud HTML'da oldindan bor, JS faqat matnni almashtiradi
const savatXabar = document.querySelector("#savat-xabar");
savatXabar.textContent = "Osh savatga qo'shildi";Birinchi variantda ekran o'quvchi yangi hududni endigina "ko'rdi" — u hali uni kuzatmayapti va birinchi matnni o'tkazib yuborishi mumkin. Malika hech narsa eshitmaydi. Ikkinchi variantda hudud sahifa ochilganidan beri bor, ekran o'quvchi uni kuzatib turibdi — matn o'zgarishi bilan e'lon qiladi.
Qoida: aria-live hududni createElement bilan yaratmang — uni HTML'da bo'sh holda qoldiring va faqat textContent ni almashtiring. Dinamik UI'dagi boshqa qulaylik qoidalari — Dinamik UI'da qulaylik darsida.
10. DevTools: DOM'ni kim o'zgartirdi?
Element yaratish va o'chirish ko'paygan sari yangi turdagi savol paydo bo'ladi: "Bu qator qayerdan keldi?" yoki "Kim savatni bo'shatib qo'ydi?". Kod katta bo'lsa, javobni topish qiyin. DevTools'da buning uchun maxsus to'xtash nuqtasi bor.
- Elements panelida kuzatmoqchi bo'lgan elementni (masalan
ul#savat) o'ng tugma bilan bosing. - Break on → subtree modifications ni tanlang. Element yonida ko'k nuqta paydo bo'ladi.
- Sahifada savatni o'zgartiradigan harakatni qiling (masalan «Qo'shish va o'chirish — jonli» bo'limidagi tugmani bosing).
Brauzer kodni aynan append yoki remove qatorida to'xtatadi va Sources panelida shu qatorni ko'rsatadi. O'ng tomondagi Call Stack esa bu qatorga qaysi funksiyalar orqali kelinganini aytadi. Bu — DevTools bilan debug darsidagi breakpoint, faqat qator raqami bilan emas, "DOM o'zgarganda" sharti bilan.
Yana ikki variant bor: attribute modifications (atribut o'zgarganda — masalan, kim class ni almashtirdi) va node removal (elementning o'zi o'chirilganda).
Tekshirib ko'ring: Sahifada bitta taom qatori har safar ikki marta qo'shilyapti. "subtree modifications" to'xtash nuqtasi sizga nimani ko'rsatadi?
Javob
Brauzer har append da to'xtaydi — demak ikki marta. Har safar Call Stack'ga qarab, append qaysi yo'l bilan chaqirilganini ko'rasiz. Ko'pincha sabab — funksiya ikki joydan chaqirilgan (masalan, ham sahifa ochilganda, ham tugma bosilganda) yoki tinglovchi ikki marta qo'shilgan (addEventListener asoslari darsida batafsil).
11. Ko'p uchraydigan xatolar
11.1 Teg nomini burchak qavs bilan yozish
<ul id="menyu"></ul>
<script>
const li = document.createElement("<li>");
</script>Konsolda:
Uncaught InvalidCharacterError: Failed to execute 'createElement' on 'Document': The tag name provided ('<li>') is not a valid name.Tarjimasi: "Document da createElement ni bajarib bo'lmadi: berilgan teg nomi ('<li>') yaroqli nom emas". Tuzatish: createElement("li") — faqat nom.
11.2 appendChild ga satr berish
<ul id="menyu"></ul>
<script>
document.querySelector("#menyu").appendChild("Osh");
</script>Konsolda:
Uncaught TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.Tarjimasi: "Node da appendChild ni bajarib bo'lmadi: 1-parametr Node turida emas". Eski appendChild faqat tugun qabul qiladi. Tuzatish: append("Osh") — u satrni o'zi matn tuguniga aylantiradi.
11.3 Bitta elementni sikl ichida qayta-qayta qo'shish
<ul id="menyu"></ul>
<script>
const menyu = document.querySelector("#menyu");
const li = document.createElement("li");
for (const nom of ["Osh", "Manti", "Lag'mon"]) {
li.textContent = nom;
menyu.append(li);
}
console.log(menyu.children.length, menyu.textContent);
</script>Konsolda:
1 Lag'monUchta qator kutilgan edi — bitta chiqdi. createElement sikldan tashqarida: bitta element yaratildi va har aylanishda o'sha element "ko'chirildi" — joyidan o'z joyiga («Mavjud elementni ko'chirish» bo'limi). Oxirida unda oxirgi nom qoldi. Tuzatish: createElement ni sikl ichiga olib kiring — har aylanishda yangi element.
11.4 Yaratib, qo'shishni unutish
Xato ham, natija ham yo'q — element xotirada qoldi. Shubha bo'lsa: console.log(el.isConnected).
11.5 Nusxadagi takroriy id
cloneNode(true) dan keyin id ni olib tashlang yoki o'zgartiring. Aks holda getElementById va label for noto'g'ri elementga bog'lanadi.
12. Mashqlar
1-mashq (oson): Aksiya bloki
Sarlavhadan keyin, menyudan oldin p yarating: class'i aksiya, matni Bugun ko'k choy bepul!. Keyin body bolalarining ro'yxatini chiqaring. Kutilgan natija: HTMLCollection(4) [h2, p.aksiya, ul, script].
<h2>Menyu</h2>
<ul>
<li>Osh</li>
</ul>
<script>
// shu yerga yozing
</script>Yechim
<h2>Menyu</h2>
<ul>
<li>Osh</li>
</ul>
<script>
const aksiya = document.createElement("p");
aksiya.classList.add("aksiya");
aksiya.textContent = "Bugun ko'k choy bepul!";
document.querySelector("h2").after(aksiya);
console.log(document.body.children);
</script>Konsolda:
HTMLCollection(4) [h2, p.aksiya, ul, script]document.querySelector("ul").before(aksiya) ham to'g'ri — joy bir xil. aksiya — «Bahor»ning kanonik class'i.
2-mashq (o'rta): Bronlar jadvali
bronlar massividan jadval qatorlarini (tr) yarating: har qatorda ikki katak (td) — ism va odam soni. Qatorlarni tbody ga qo'shing. Oxirida jami odam sonini chiqaring. Kutilgan natija: Jami: 9 kishi.
Ishora: har bron uchun createElement("tr"), ichiga ikki createElement("td"); bir nechta elementni bitta append bilan qo'shish mumkin («Bir nechta narsa va matn» bo'limi).
<table>
<thead><tr><th>Ism</th><th>Odam</th></tr></thead>
<tbody id="bronlar"></tbody>
</table>
<script>
const bronlar = [
{ ism: "Malika", odam: 2 },
{ ism: "Bobur", odam: 4 },
{ ism: "Sardor", odam: 3 },
];
// shu yerga yozing
</script>Yechim
<table>
<thead><tr><th>Ism</th><th>Odam</th></tr></thead>
<tbody id="bronlar"></tbody>
</table>
<script>
const bronlar = [
{ ism: "Malika", odam: 2 },
{ ism: "Bobur", odam: 4 },
{ ism: "Sardor", odam: 3 },
];
const tbody = document.querySelector("#bronlar");
let jami = 0;
for (const bron of bronlar) {
const tr = document.createElement("tr");
const ism = document.createElement("td");
ism.textContent = bron.ism;
const odam = document.createElement("td");
odam.textContent = bron.odam;
tr.append(ism, odam);
tbody.append(tr);
jami += bron.odam;
}
console.log(`Jami: ${jami} kishi`);
</script>Konsolda:
Jami: 9 kishitbody HTML'da oldindan bor — DOM daraxti darsida ko'rganingizdek, tr ni to'g'ridan-to'g'ri table ga qo'shmaslik kerak. Ismlar textContent bilan — serverdan kelgan ism ham xavfsiz.
3-mashq (qiyin): Taomni menyudan savatga
Har taom qatorida "Savatga" tugmasi bor. Kod sahifa ochilganda ikkinchi taomni (Manti) savatga ko'chirsin: li ni savat ro'yxatiga append qiling va undagi tugmani remove() qiling. So'ng, osh qatorini nusxalab (cloneNode(true)), nusxani ham savatga qo'shing, uning tugmasini ham olib tashlang. Oxirida ikki ro'yxatdagi qatorlar sonini chiqaring. Kutilgan natija: Menyu: 2, savat: 2.
<h3>Menyu</h3>
<ul id="menyu">
<li>Osh <button type="button">Savatga</button></li>
<li>Manti <button type="button">Savatga</button></li>
<li>Lag'mon <button type="button">Savatga</button></li>
</ul>
<h3>Savat</h3>
<ul id="savat"></ul>
<script>
// shu yerga yozing
</script>Yechim
<h3>Menyu</h3>
<ul id="menyu">
<li>Osh <button type="button">Savatga</button></li>
<li>Manti <button type="button">Savatga</button></li>
<li>Lag'mon <button type="button">Savatga</button></li>
</ul>
<h3>Savat</h3>
<ul id="savat"></ul>
<script>
const menyu = document.querySelector("#menyu");
const savat = document.querySelector("#savat");
const manti = menyu.children[1];
savat.append(manti);
manti.querySelector("button").remove();
const osh = menyu.children[0];
const nusxa = osh.cloneNode(true);
nusxa.querySelector("button").remove();
savat.append(nusxa);
const soni = `Menyu: ${menyu.children.length}`;
console.log(`${soni}, savat: ${savat.children.length}`);
</script>Konsolda:
Menyu: 2, savat: 2Manti ko'chdi — menyuda qolmadi (3 → 2). Osh esa nusxalandi — menyuda ham, savatda ham bor. Bitta muhim joy: manti ni ko'chirgandan keyin menyu.children[1] endi Lag'mon bo'lardi — children jonli. Shuning uchun oshni children[0] dan oldik: u o'zgarmadi. Nusxadan tugmani nusxa sahifaga qo'shilishidan oldin olib tashladik — xotirada ishlash tezroq.
4-mashq: Portfolio qadami — kartalarga texnologiya teglari
Portfolio'ning loyihalar/index.html sahifasidagi kartalar (Yakuniy loyiha dagi .loyihalar va article tuzilmasi) HTML'da qoladi: portfolio — sizning asosiy ko'rgazmangiz, u JavaScript o'chiq bo'lsa ham va qidiruv tizimi uchun ham to'liq ko'rinishi kerak. JavaScript esa unga faqat qo'shimcha yasaydi. Bu — tanish yondashuv, Brauzer mosligi va progressive enhancement darsidan: asos HTML'da ishlaydi, JavaScript uni boyitadi.
- HTML'da har
articlega (majburiy)data-texnologiyalaratributini qo'shing — bo'sh joy bilan ajratilgan ro'yxat:data-texnologiyalar="HTML CSS"(dataset). Bitta nom ichida bo'sh joy bo'lmasin: ko'p so'zli nom chiziqcha bilan yoziladi (GitHub-Pages), chunki keyingi darslarda filtr ham shu ro'yxatni bo'sh joy bo'yicha bo'ladi. asosiy.jsgateglarniChiz()funksiyasini yozing..loyihalarbo'lmasa — jim tugasin. Har karta uchun ro'yxatnisplit(" ")bilan bo'ling (Kesish va bo'lish) va har texnologiya uchunsmallelementini yarating. Teglarni kartaning tavsif paragrafi (p:nth-of-type(2)) ichiga, oxiriga qo'ying — kartaga yangi bola qo'shmang: subgrid har kartada aynan 4 qatorni kutadi.- Atributni unutgan karta bo'lsa, funksiya unga tegmasin — jim o'tkazib yuborsin. Sahifani qayta ishlatganda teglar ikki marta chiqmasligi uchun avval eskisini (
.teglarbo'lsa)remove()qiling. .loyihalardan oldin hisoblagich paragrafini yarating:2 ta loyiha(before),id="loyihalar-soni"bilan — u ham qayta chaqirilganda avval o'chirilsin.
Commit: JS: loyiha kartalariga texnologiya teglarini qo'sh.
Yechim
HTML (har kartada, qolgan qatorlar o'zgarmaydi):
<article data-texnologiyalar="HTML CSS Git">asosiy.js:
function teglarniChiz() {
const joy = document.querySelector(".loyihalar");
if (joy === null) {
return;
}
const kartalar = joy.querySelectorAll(":scope > article");
for (const karta of kartalar) {
const royxat = karta.dataset.texnologiyalar;
if (royxat === undefined) {
continue;
}
const tavsif = karta.querySelector("p:nth-of-type(2)");
tavsif.querySelector(".teglar")?.remove();
const teglar = document.createElement("span");
teglar.classList.add("teglar");
for (const nom of royxat.split(" ")) {
const teg = document.createElement("small");
teg.textContent = nom;
teglar.append(" ", teg);
}
tavsif.append(teglar);
}
document.querySelector("#loyihalar-soni")?.remove();
const soni = document.createElement("p");
soni.id = "loyihalar-soni";
soni.textContent = `${kartalar.length} ta loyiha`;
joy.before(soni);
}
teglarniChiz();Ikki karta bilan tekshiramiz (sahifadagi tuzilmaning qisqa nusxasi):
<style>
.teglar small {
margin-inline-start: 4px; padding: 0 6px;
border: 1px solid #c9d6cf; border-radius: 8px;
}
</style>
<main>
<h1>Loyihalar</h1>
<div class="loyihalar">
<article data-texnologiyalar="HTML CSS Git">
<h2>Choyxona «Bahor» sayti</h2>
<p><time datetime="2026-09">2026-yil sentabr</time></p>
<p>To'rt sahifali sayt: menyu, bron formasi.</p>
<ul role="list"><li><a href="#">Saytni ochish</a></li></ul>
</article>
<article>
<h2>Semantik blog maqolasi</h2>
<p><time datetime="2026-08">2026-yil avgust</time></p>
<p>"Osh sirlari" maqolasi.</p>
<ul role="list"><li><a href="#">Saytni ochish</a></li></ul>
</article>
</div>
</main>
<script>
function teglarniChiz() {
const joy = document.querySelector(".loyihalar");
if (joy === null) {
return;
}
const kartalar = joy.querySelectorAll(":scope > article");
for (const karta of kartalar) {
const royxat = karta.dataset.texnologiyalar;
if (royxat === undefined) {
continue;
}
const tavsif = karta.querySelector("p:nth-of-type(2)");
tavsif.querySelector(".teglar")?.remove();
const teglar = document.createElement("span");
teglar.classList.add("teglar");
for (const nom of royxat.split(" ")) {
const teg = document.createElement("small");
teg.textContent = nom;
teglar.append(" ", teg);
}
tavsif.append(teglar);
}
document.querySelector("#loyihalar-soni")?.remove();
const soni = document.createElement("p");
soni.id = "loyihalar-soni";
soni.textContent = `${kartalar.length} ta loyiha`;
joy.before(soni);
}
teglarniChiz();
teglarniChiz();
const birinchi = document.querySelector("article");
console.log(birinchi.children.length);
console.log(birinchi.querySelectorAll("small").length);
console.log(document.querySelector("#loyihalar-soni"));
</script>Konsolda:
4
3
<p id="loyihalar-soni">2 ta loyiha</p>Funksiyani ataylab ikki marta chaqirdik: teglar baribir uchta — eskisi remove() bilan o'chdi va yangisi yasaldi. Karta bolalari hamon 4 ta — subgrid buzilmaydi. Ikkinchi kartada atribut yo'q — unga tegilmadi. Hisoblagich ham bitta: before har chaqiruvda yangi p qo'shardi, lekin #loyihalar-soni avval o'chirildi. "Avval eskisini olib tashla, keyin yangisini qo'y" — qayta chiziladigan har qism uchun ishonchli qolip.
:scope > article — Elementlarni tanlash darsidagi usul: faqat .loyihalar ning bevosita bolalari. ?.remove() — .teglar bo'lmasa (birinchi chaqiruv), hech narsa qilmaydi (optional chaining). .teglar — shu qadam uchun yangi class nomi.
Nega kartalarni massivdan yasamadik? Bu ham mumkin edi, lekin unda JavaScript o'chiq bo'lganda va qidiruv tizimi sahifani o'qiganda kartalar ko'rinmay qolardi — portfolio uchun bu katta yo'qotish. Shuning uchun ma'lumot HTML'da, JavaScript faqat bezaydi. Ro'yxatni ma'lumotdan oldindan (yig'ish vaqtida) yasash — Next.js qismida (Portfolio v2).
Tekshirib ko'ring: Teglarni tavsif
pning ichiga emas,karta.append(teglar)bilan kartaning oxiriga qo'ysak nima buziladi?
Javob
Karta beshinchi bolaga ega bo'lardi. Portfolio CSS'idagi subgrid har kartaga 4 qator ajratgan (span 4) — beshinchi bola qatorlarga sig'maydi va kartalar orasidagi bir chiziq (sarlavhalar, sanalar bir balandlikda) buziladi. Shuning uchun yangi narsa mavjud bolaning ichiga qo'yildi.
13. Real ishda
- Har bir ro'yxatli interfeys — Telegram'dagi xabarlar, marketpleysdagi mahsulotlar, Click'dagi to'lovlar tarixi — "ma'lumot massivi → element yasovchi funksiya →
append" qolipi bilan quriladi. Freymvorklar (React — kursda alohida o'rganamiz) buni avtomatlashtiradi, lekin ichida aynan shucreateElementvaappendishlaydi. - Xavfsizlik auditida
innerHTMLvainsertAdjacentHTMLqidiriladi.createElement+textContentbilan yozilgan kod bu ro'yxatga tushmaydi — tekshiruvchiga ham, sizga ham oson. - Ko'chirish — sudrab-tashlash (drag and drop) ro'yxatlarining asosi: Trello'ga o'xshash taxtada karta bir ustundan boshqasiga
appendbilan o'tadi. - Intervyuda so'raladi: "
appendvaappendChildfarqi?", "Elementni qanday o'chirasiz?", "cloneNode(true)nimani nusxalamaydi?" (javob:addEventListenertinglovchilarini).
Xulosa
- Yangi element:
createElement→ sozlash (textContent,classList,dataset) →append. Qo'shilmaguncha u faqat xotirada. - Joy:
prepend/append— ichiga,before/after— yoniga; satr argumentlar — xavfsiz matn. - Mavjud elementni qo'shish — ko'chirish, nusxa emas; nusxa uchun
cloneNode(true)(vaidni o'zgartiring). replaceWith— almashtiradi,remove— o'chiradi; o'chirilgan element o'zgaruvchida qoladi.insertAdjacentHTMLmavjud elementlarga tegmaydi, lekin HTML o'qiydi — faqat o'zingizning satringiz uchun.- Massivdan ro'yxat: element yasovchi funksiya +
for...of+append.
Keyingi dars: DOM bo'ylab harakatlanish — elementdan otasiga, bolalariga va qo'shnilariga o'tish: parentElement, nextElementSibling va boshqalar.
Manbalar
- MDN: "Document: createElement() method", "Element: append() method", "Element: before() method" — developer.mozilla.org
- MDN: "Element: replaceWith() method", "Element: remove() method", "Node: cloneNode() method" — developer.mozilla.org
- MDN: "Element: insertAdjacentHTML() method", "Element: moveBefore() method" — developer.mozilla.org
- web-features: "move-before" — github.com/web-platform-dx/web-features
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!