13-bo‘lim

DOM ni o'zgartirish

Element yaratish, qo'shish va o'chirish, uslublarni boshqarish, ro'yxatni chizish va samaradorlik masalalari.

🕑 16 daqiqa o‘qish 📄 553 so‘z 👁 1 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Element yaratish
  2. Joylashtirish usullari
  3. O'chirish va almashtirish
  4. Uslublar
  5. Ro'yxatni chizish
  6. Fragment bilan samaradorlik
  7. Nusxa olish
  8. template tegi
  9. insertAdjacentHTML
  10. Xulosa

Oldingi bo'limda elementlarni o'qidik. Endi ularni yaratamiz va o'zgartiramiz.

JavaScript
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 #

JavaScript
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);
Natija
Elementlar soni: 3
Oxirgi element : Sport bilan shug'ullanish
data-id        : 3
HTML da klass  : vazifa

Joylashtirish usullari #

JavaScript
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"));
Natija
boshiga
birinchidan keyin
Non olish
Kitob o'qish
oxirgidan oldin
oxiriga
Element qayerga qo'yiladi? Ota element mavjud bola mavjud bola before() prepend() appendChild() after() yashil - ota bilan bir darajada sariq - ota ichida
prepend/append ota ichiga, before/after esa yoniga qo'yadi

O'chirish va almashtirish #

JavaScript
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);
Natija
Boshida: 2
remove dan keyin: 1
Oxirgi element: almashtirildi
Tozalangandan keyin: 0
Tozalashning uch usuli
JavaScript
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:
JavaScript
royxat.replaceChildren(...yangiElementlar);

innerHTML = "" ham tez, lekin u brauzerni satrni tahlil qilishga majbur qiladi va hodisa ishlovchilarini uzib qo'yadi.

Uslublar #

JavaScript
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);
Natija
color        : red
background   : yellow
Inline HTML  : color: red; background-color: yellow; font-size: 20px;
CSS o'zgaruvchi: blue
padding      : 10px
Uslubni JavaScript da emas, CSS da yozing
JavaScript
// YOMON - uslub kodga aralashib ketadi
element.style.color = "red";
element.style.fontWeight = "bold";
element.style.border = "2px solid red";
JavaScript
// YAXSHI - klass qo'shasiz, uslub CSS da qoladi
element.classList.add("xato");
CSS
.xato {
    color: red;
    font-weight: bold;
    border: 2px solid red;
}

Afzalliklari:

  • Dizayn CSS da bir joyda turadi;
  • Media so'rovlar va :hover ishlaydi;
  • 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:

JavaScript
panel.style.width = `${foiz}%`;

Diqqat: element.style faqat inline uslubni ko'rsatadi. CSS faylidagi qiymatni o'qish uchun:

JavaScript
getComputedStyle(element).color

Ro'yxatni chizish #

JavaScript
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);
Natija
Elementlar    : 3
Bajarilganlar : 1
Ikkinchi matn : Kitob o'qish
Ikkinchi klass: vazifa

Fragment bilan samaradorlik #

JavaScript
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);
Natija
Sekin usul  : 100
Tez usul    : 100
Natija bir xilmi?: true
DocumentFragment - DOM ga tegmaydigan idish

Har 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:

JavaScript
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 #

JavaScript
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);
Natija
Asl bolalari    : 1
Sayoz nusxa     : 0
Chuqur nusxa    : 1
Klass ko'chdimi?: karta
Bir obyektmi?   : false

template tegi #

JavaScript
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);
Natija
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:

JavaScript
// 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 #

JavaScript
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);
Natija
Element ichi: <b>ichida-boshida</b>markaz<i>ichida-oxirida</i>
Oldingi qo'shni: oldin
Keyingi qo'shni: keyin
PozitsiyaQayerga
beforebeginElementdan oldin
afterbeginElement ichida, boshida
beforeendElement ichida, oxirida
afterendElementdan keyin
insertAdjacentHTML ham XSS ga ochiq

innerHTML kabi, bu metod ham satrni HTML sifatida tahlil qiladi:

JavaScript
el.insertAdjacentHTML("beforeend", foydalanuvchiMatni);   // XAVFLI

Foydalanuvchi ma'lumoti bo'lsa - insertAdjacentText ishlating:

JavaScript
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.

Amaliy topshiriq
  1. createElement bilan element yaratib, ro'yxatga qo'shing.
  2. prepend, after, before farqini sinab ko'ring.
  3. remove va replaceWith bilan elementni almashtiring.
  4. replaceChildren() bilan ro'yxatni tozalang.
  5. style orqali uslub bering va getAttribute("style") ni ko'ring.
  6. Uslub o'rniga klass ishlatish afzalligini tushuntiring.
  7. Massivdan map bilan elementlar yasab, bir marta joylang.
  8. DocumentFragment bilan 100 ta element qo'shing.
  9. <template> yaratib, undan ikki karta yasang.
  10. insertAdjacentHTML ning to'rt pozitsiyasini sinang.

Xulosa #

  • createElement + textContent + appendChild - asosiy uchlik.
  • prepend/append ota ichiga, before/after yoniga.
  • replaceChildren() - tozalashning eng toza usuli.
  • Uslubni JavaScript da emas, CSS klassida yozing.
  • element.style faqat inline uslubni ko'rsatadi.
  • CSS fayldagi qiymat uchun getComputedStyle.
  • DocumentFragment ko'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.
  • insertAdjacentHTML ham XSS ga ochiq - insertAdjacentText ishlating.

Keyingi bo'limda hodisalar bilan ishlashni o'rganamiz.

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.