13-bo‘lim
DOM ni o'zgartirish
Element yaratish, qo'shish va o'chirish, uslublarni boshqarish, ro'yxatni chizish va samaradorlik masalalari.
Ushbu bo‘lim mundarijasi
Oldingi bo'limda elementlarni o'qidik. Endi ularni yaratamiz va o'zgartiramiz.
document.body.innerHTML = `
<div id="ilova">
<ul id="royxat">
<li class="vazifa" data-id="1">Non olish</li>
<li class="vazifa" data-id="2">Kitob o'qish</li>
</ul>
</div>`;
Element yaratish #
const yangi = document.createElement("li");
yangi.className = "vazifa";
yangi.textContent = "Sport bilan shug'ullanish";
yangi.dataset.id = "3";
const royxat = document.getElementById("royxat");
royxat.appendChild(yangi);
console.log("Elementlar soni:", royxat.children.length);
console.log("Oxirgi element :", royxat.lastElementChild.textContent);
console.log("data-id :", royxat.lastElementChild.dataset.id);
console.log("HTML da klass :", royxat.lastElementChild.className);
Elementlar soni: 3
Oxirgi element : Sport bilan shug'ullanish
data-id : 3
HTML da klass : vazifa
Joylashtirish usullari #
const royxat = document.getElementById("royxat");
function yaratish(matn) {
const el = document.createElement("li");
el.textContent = matn;
return el;
}
royxat.appendChild(yaratish("oxiriga"));
royxat.prepend(yaratish("boshiga"));
royxat.firstElementChild.after(yaratish("birinchidan keyin"));
royxat.lastElementChild.before(yaratish("oxirgidan oldin"));
const matnlar = [...royxat.children].map((e) => e.textContent);
console.log(matnlar.join("\n"));
boshiga
birinchidan keyin
Non olish
Kitob o'qish
oxirgidan oldin
oxiriga
O'chirish va almashtirish #
const royxat = document.getElementById("royxat");
console.log("Boshida:", royxat.children.length);
royxat.firstElementChild.remove();
console.log("remove dan keyin:", royxat.children.length);
const oxirgi = royxat.lastElementChild;
const orin = document.createElement("li");
orin.textContent = "almashtirildi";
oxirgi.replaceWith(orin);
console.log("Oxirgi element:", royxat.lastElementChild.textContent);
// Hammasini tozalash
royxat.replaceChildren();
console.log("Tozalangandan keyin:", royxat.children.length);
Boshida: 2
remove dan keyin: 1
Oxirgi element: almashtirildi
Tozalangandan keyin: 0
element.replaceChildren(); // eng toza (zamonaviy)
element.innerHTML = ""; // ishlaydi, lekin HTML tahlil qiladi
while (element.firstChild) { // eski usul
element.removeChild(element.firstChild);
}
replaceChildren() afzal:
- HTML tahlilchisini ishga tushirmaydi;
- Bir vaqtda yangi bolalarni ham qo'yish mumkin:
royxat.replaceChildren(...yangiElementlar);
innerHTML = "" ham tez, lekin u brauzerni satrni tahlil
qilishga majbur qiladi va hodisa ishlovchilarini uzib qo'yadi.
Uslublar #
const el = document.createElement("div");
document.body.appendChild(el);
el.style.color = "red";
el.style.backgroundColor = "yellow"; // camelCase!
el.style.fontSize = "20px";
console.log("color :", el.style.color);
console.log("background :", el.style.backgroundColor);
console.log("Inline HTML :", el.getAttribute("style"));
// CSS o'zgaruvchilari
el.style.setProperty("--asosiy-rang", "blue");
console.log("CSS o'zgaruvchi:", el.style.getPropertyValue("--asosiy-rang"));
// Bir nechta uslubni birga
Object.assign(el.style, { padding: "10px", margin: "5px" });
console.log("padding :", el.style.padding);
color : red
background : yellow
Inline HTML : color: red; background-color: yellow; font-size: 20px;
CSS o'zgaruvchi: blue
padding : 10px
// YOMON - uslub kodga aralashib ketadi
element.style.color = "red";
element.style.fontWeight = "bold";
element.style.border = "2px solid red";
// YAXSHI - klass qo'shasiz, uslub CSS da qoladi
element.classList.add("xato");
.xato {
color: red;
font-weight: bold;
border: 2px solid red;
}
Afzalliklari:
- Dizayn CSS da bir joyda turadi;
- Media so'rovlar va
:hoverishlaydi; - Qorong'i rejimga moslash oson;
- Kodni o'qish osonlashadi.
style ni faqat hisoblangan qiymatlar uchun ishlating -
masalan sudrab siljitiladigan elementning koordinatasi yoki
progress panelining eni:
panel.style.width = `${foiz}%`;
Diqqat: element.style faqat inline uslubni ko'rsatadi.
CSS faylidagi qiymatni o'qish uchun:
getComputedStyle(element).color
Ro'yxatni chizish #
const vazifalar = [
{ id: 1, matn: "Non olish", bajarildi: true },
{ id: 2, matn: "Kitob o'qish", bajarildi: false },
{ id: 3, matn: "Sport", bajarildi: false }
];
function chizish(royxat, malumot) {
const bolaklar = malumot.map((v) => {
const li = document.createElement("li");
li.className = v.bajarildi ? "vazifa bajarilgan" : "vazifa";
li.dataset.id = String(v.id);
li.textContent = v.matn;
return li;
});
royxat.replaceChildren(...bolaklar);
}
const royxat = document.getElementById("royxat");
chizish(royxat, vazifalar);
console.log("Elementlar :", royxat.children.length);
console.log("Bajarilganlar :", royxat.querySelectorAll(".bajarilgan").length);
console.log("Ikkinchi matn :", royxat.children[1].textContent);
console.log("Ikkinchi klass:", royxat.children[1].className);
Elementlar : 3
Bajarilganlar : 1
Ikkinchi matn : Kitob o'qish
Ikkinchi klass: vazifa
Fragment bilan samaradorlik #
const royxat = document.getElementById("royxat");
// Har qo'shishda DOM o'zgaradi - sekin
function sekin(soni) {
royxat.replaceChildren();
for (let i = 0; i < soni; i++) {
const li = document.createElement("li");
li.textContent = `element ${i}`;
royxat.appendChild(li); // har safar DOM ga tegadi
}
}
// Fragmentda yig'ib, bir marta qo'shish - tez
function tez(soni) {
const fragment = document.createDocumentFragment();
for (let i = 0; i < soni; i++) {
const li = document.createElement("li");
li.textContent = `element ${i}`;
fragment.appendChild(li); // xotirada, DOM tegilmaydi
}
royxat.replaceChildren(fragment); // bitta amal
}
sekin(100);
console.log("Sekin usul :", royxat.children.length);
tez(100);
console.log("Tez usul :", royxat.children.length);
console.log("Natija bir xilmi?:", royxat.children.length === 100);
Sekin usul : 100
Tez usul : 100
Natija bir xilmi?: true
DocumentFragment - DOM ga tegmaydigan idishHar appendChild chaqiruvi brauzerni joylashuvni qayta
hisoblashga majbur qilishi mumkin. Ming marta qo'shsangiz -
ming marta hisoblash.
DocumentFragment - xotiradagi vaqtinchalik idish. Unga
qo'shish DOM ga ta'sir qilmaydi. Oxirida uni bir marta
joylashtirasiz va bitta qayta hisoblash bo'ladi.
Muhim xossa: fragment DOM ga qo'shilganda o'zi yo'qoladi, faqat bolalari ko'chadi.
Zamonaviy brauzerlar o'zgarishlarni paketlab bajaradi, shuning uchun farq ilgarigidek katta emas. Lekin o'lchashga majbur qiladigan kod baribir sekin:
for (const el of elementlar) {
el.style.height = el.offsetHeight + 10 + "px"; // har safar o'lchaydi
}
Bu "layout thrashing" deb ataladi. Yechim - avval hammasini o'qib, keyin hammasini yozish.
Nusxa olish #
const asl = document.createElement("div");
asl.className = "karta";
asl.innerHTML = "<span>ichki matn</span>";
const sayoz = asl.cloneNode(false);
const chuqur = asl.cloneNode(true);
console.log("Asl bolalari :", asl.children.length);
console.log("Sayoz nusxa :", sayoz.children.length);
console.log("Chuqur nusxa :", chuqur.children.length);
console.log("Klass ko'chdimi?:", chuqur.className);
console.log("Bir obyektmi? :", asl === chuqur);
Asl bolalari : 1
Sayoz nusxa : 0
Chuqur nusxa : 1
Klass ko'chdimi?: karta
Bir obyektmi? : false
template tegi #
document.body.insertAdjacentHTML("beforeend", `
<template id="kartaShablon">
<div class="karta">
<h3 class="karta__sarlavha"></h3>
<p class="karta__matn"></p>
</div>
</template>`);
const shablon = document.getElementById("kartaShablon");
function kartaYaratish(sarlavha, matn) {
const nusxa = shablon.content.cloneNode(true);
nusxa.querySelector(".karta__sarlavha").textContent = sarlavha;
nusxa.querySelector(".karta__matn").textContent = matn;
return nusxa;
}
const idish = document.createElement("div");
idish.appendChild(kartaYaratish("Birinchi", "Matn bir"));
idish.appendChild(kartaYaratish("Ikkinchi", "Matn ikki"));
console.log("Kartalar soni:", idish.querySelectorAll(".karta").length);
console.log("Birinchi :", idish.querySelector("h3").textContent);
console.log("Shablon DOM da ko'rinadimi?:",
document.querySelectorAll(".karta").length === 0);
Kartalar soni: 2
Birinchi : Birinchi
Shablon DOM da ko'rinadimi?: true
<template> - takrorlanuvchi tuzilma uchun<template> ichidagi HTML ko'rsatilmaydi va uning
skriptlari ishlamaydi. U faqat namuna sifatida turadi.
Afzalligi - tuzilma HTML da qoladi, JavaScript da satr sifatida emas:
// Yomon - HTML kod ichida
const html = `<div class="karta"><h3>${sarlavha}</h3></div>`;
// Yaxshi - HTML o'z joyida, JS faqat to'ldiradi
const nusxa = shablon.content.cloneNode(true);
nusxa.querySelector("h3").textContent = sarlavha;
Ikkinchi variant XSS dan ham himoyalangan - textContent
ishlatilgani uchun.
shablon.content - bu DocumentFragment, shuning uchun uni
cloneNode(true) bilan nusxalab ishlatasiz. Nusxalamasdan
qo'shsangiz, shablon bo'shab qoladi.
insertAdjacentHTML #
const el = document.createElement("div");
el.textContent = "markaz";
document.body.appendChild(el);
el.insertAdjacentHTML("beforebegin", "<span>oldin</span>");
el.insertAdjacentHTML("afterbegin", "<b>ichida-boshida</b>");
el.insertAdjacentHTML("beforeend", "<i>ichida-oxirida</i>");
el.insertAdjacentHTML("afterend", "<span>keyin</span>");
console.log("Element ichi:", el.innerHTML);
console.log("Oldingi qo'shni:", el.previousElementSibling.textContent);
console.log("Keyingi qo'shni:", el.nextElementSibling.textContent);
Element ichi: <b>ichida-boshida</b>markaz<i>ichida-oxirida</i>
Oldingi qo'shni: oldin
Keyingi qo'shni: keyin
| Pozitsiya | Qayerga |
|---|---|
beforebegin | Elementdan oldin |
afterbegin | Element ichida, boshida |
beforeend | Element ichida, oxirida |
afterend | Elementdan keyin |
insertAdjacentHTML ham XSS ga ochiqinnerHTML kabi, bu metod ham satrni HTML sifatida tahlil
qiladi:
el.insertAdjacentHTML("beforeend", foydalanuvchiMatni); // XAVFLI
Foydalanuvchi ma'lumoti bo'lsa - insertAdjacentText ishlating:
el.insertAdjacentText("beforeend", foydalanuvchiMatni); // xavfsiz
Yoki element yaratib, textContent bilan to'ldiring.
Umumiy qoida: innerHTML, outerHTML va
insertAdjacentHTML - faqat o'zingiz yozgan HTML uchun.
Tashqaridan kelgan har qanday ma'lumot uchun textContent.
createElementbilan element yaratib, ro'yxatga qo'shing.prepend,after,beforefarqini sinab ko'ring.removevareplaceWithbilan elementni almashtiring.replaceChildren()bilan ro'yxatni tozalang.styleorqali uslub bering vagetAttribute("style")ni ko'ring.- Uslub o'rniga klass ishlatish afzalligini tushuntiring.
- Massivdan
mapbilan elementlar yasab, bir marta joylang. DocumentFragmentbilan 100 ta element qo'shing.<template>yaratib, undan ikki karta yasang.insertAdjacentHTMLning to'rt pozitsiyasini sinang.
Xulosa #
createElement+textContent+appendChild- asosiy uchlik.prepend/appendota ichiga,before/afteryoniga.replaceChildren()- tozalashning eng toza usuli.- Uslubni JavaScript da emas, CSS klassida yozing.
element.stylefaqat inline uslubni ko'rsatadi.- CSS fayldagi qiymat uchun
getComputedStyle. DocumentFragmentko'p element qo'shishda qayta hisoblashni kamaytiradi.- Avval hammasini o'qing, keyin hammasini yozing (layout thrashing).
cloneNode(true)chuqur,cloneNode(false)sayoz nusxa.<template>takrorlanuvchi tuzilmani HTML da saqlaydi.insertAdjacentHTMLham XSS ga ochiq -insertAdjacentTextishlating.
Keyingi bo'limda hodisalar bilan ishlashni o'rganamiz.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
Xatolik topdingizmi?
Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.