IlmHamroh
JavaScript Full-stack/9-qism. JavaScript brauzerda va debugging5/29-dars20 daqiqa
Mundarija (38)

HTML atributlari JavaScript'da: getAttribute, setAttribute, xususiyatlar va dataset

Qisqacha: Atribut — HTML'da yozilgan narsa (value="Ali"), xususiyat (property) — JavaScript obyektidagi jonli qiymat (input.value). Atributni getAttribute, setAttribute, removeAttribute va toggleAttribute boshqaradi; ko'p atributning xususiyat "egizagi" ham bor. Ular har doim bir xil emas: foydalanuvchi maydonga yozsa, value xususiyati o'zgaradi, atribut esa yo'q. O'z ma'lumotingiz uchun data-* atributlari va element.dataset ishlatiladi.

Bu darsda

  • getAttribute, setAttribute, hasAttribute, removeAttribute va toggleAttribute bilan atributlarni boshqara olasiz.
  • Atribut va xususiyat farqini, ular qachon bir-birini aks ettirishini tushuntira olasiz.
  • value va checked dagi "ikki qiymat" tuzog'ini bilasiz.
  • Boolean va aria-* atributlarini to'g'ri qo'yasiz va olib tashlaysiz.
  • data-* atributlarini dataset orqali o'qib-yozasiz va CSS bilan bog'laysiz.

Oldin bilishingiz kerak: Kontentni o'zgartirish va XSS xavfi, Global atributlar, Atribut selektorlari, Obyekt: kalit-qiymat juftliklari.

1. Nega bu kerak?

O'tgan darsda elementning ichini o'zgartirdik. Lekin sahifadagi ko'p narsa ichida emas, atributlarda turadi. Oldingi qismlarda bir nechta va'da qoldirgan edik:

  • Atribut selektorlari darsida xatoli telefon maydoni aria-invalid="true" bilan qizil bo'lardi. "Bu atributni xato tekshirilgandan keyin JavaScript qo'yadi" degan edik.
  • Navbar va mobil menyu darsida header pastga surilganda yashirinadi — data-yashirin atributini JavaScript qo'yadi va olib tashlaydi.
  • Tugmalar tizimi darsida so'rov ketayotgan tugmaga aria-busy="true" qo'yiladi.
  • Global atributlar darsida taom kartasiga data-taom-raqami, data-achchiq, data-porsiya yozgandik: "JavaScript ularni dataset orqali o'qiydi".

Bugun shu va'dalarning hammasini bajaramiz. Yo'lda esa boshlovchilarni ko'p chalg'itadigan bitta savolga javob beramiz: input.value va input.getAttribute("value") nega har xil qiymat qaytaradi?

2. Atribut bilan ishlashning beshta metodi

2.1 O'qish va tekshirish

Atribut (attribute) — HTML tegida yozilgan nom="qiymat" juftligi (Teg, element va atribut). JavaScript'da ular uchun maxsus metodlar bor:

html
<a id="bron" href="https://example.com/bron" class="tugma">
  Stol band qilish</a>
<script>
  const bron = document.querySelector("#bron");
  console.log(bron.getAttribute("href"));
  console.log(bron.getAttribute("title"));
  console.log(bron.hasAttribute("class"), bron.hasAttribute("title"));
  console.log(bron.getAttributeNames());
</script>

Konsolda:

text
https://example.com/bron
null
true false
(3) ['id', 'href', 'class']
  • getAttribute(nom) — qiymatni satr sifatida qaytaradi. Atribut yo'q bo'lsa — null (xuddi topilmagan element kabi, undefined va null).
  • hasAttribute(nom) — bormi, yo'qmi: true yoki false.
  • getAttributeNames() — elementdagi barcha atribut nomlari massivi, HTML'dagi tartibda.

2.2 Yozish va o'chirish

html
<button id="yubor" type="submit">Yuborish</button>
<script>
  const yubor = document.querySelector("#yubor");
  yubor.setAttribute("aria-busy", "true");
  yubor.setAttribute("title", "Yuborilmoqda");
  console.log(yubor);

  yubor.removeAttribute("aria-busy");
  yubor.removeAttribute("title");
  yubor.removeAttribute("yoq-atribut");
  console.log(yubor);
</script>

Konsolda:

text
<button id="yubor" type="submit" aria-busy="true" title="Yuborilmoqda">Yuborish</button>
<button id="yubor" type="submit">Yuborish</button>

setAttribute(nom, qiymat) atribut bo'lmasa — qo'shadi, bo'lsa — qiymatini almashtiradi. removeAttribute(nom) olib tashlaydi; atribut yo'q bo'lsa ham xato bermaydi. Bu — Tugmalar tizimi darsidagi aria-busy ning JavaScript tomoni: so'rov boshlanganda qo'yiladi, javob kelganda olib tashlanadi. CSS tayyor — atribut paydo bo'lishi bilan tugma o'zgaradi.

Ikki muhim qoida:

  • setAttribute qiymatni doim satrga aylantiradi. setAttribute("data-soni", 3) — atributda "3" satri turadi.
  • HTML atribut nomlari katta-kichik harfni farqlamaydi: setAttribute("ID", "x") — oddiy id ga yozadi.

2.3 toggleAttribute — bor/yo'q almashtirgich

Ba'zi atributlarning qiymati muhim emas — faqat borligi muhim. Ular uchun toggleAttribute(nom) bor: atribut bo'lsa olib tashlaydi, bo'lmasa qo'shadi va natijani true/false bilan qaytaradi. Navbar darsidagi yashirinadigan header aynan shu bilan ishlaydi:

html
<style>
  header { background: #2f6b3a; color: #fffaf0; padding: 8px; }
  header[data-yashirin] { opacity: 0.2; }
</style>
<header>«Bahor» choyxonasi</header>
<script>
  const header = document.querySelector("header");
  console.log(header.toggleAttribute("data-yashirin"));
  console.log(header);
  console.log(header.toggleAttribute("data-yashirin", true));
  console.log(header.toggleAttribute("data-yashirin", false));
</script>

Konsolda:

text
true
<header data-yashirin="">«Bahor» choyxonasi</header>
true
false

Birinchi chaqiruv atributni qo'shdi (true — "endi bor"). Ikkinchi argument esa majburlaydi: true — "bo'lsin" (bor edi, qoldi), false — "bo'lmasin". Natijada atribut olib tashlandi va header yana to'liq ko'rinadi. "Tahrirlab ko'rish" bilan oxirgi qatorni o'chirib ko'ring — header xira bo'lib qoladi. Haqiqiy navbar'da opacity emas, translate bor va qaysi tomonga surilayotganini scroll hodisasi aytadi — bu qism keyinroq.

Tekshirib ko'ring: el.getAttribute("hidden") — element <p hidden> bo'lsa, nima qaytaradi? <p> bo'lsa-chi?

Javob

<p hidden> da — bo'sh satr "": atribut bor, qiymati yozilmagan. <p> da — null: atribut umuman yo'q. Shuning uchun borlikni getAttribute bilan emas, hasAttribute bilan tekshiring: if (el.getAttribute("hidden")) bo'sh satrni false deb biladi va noto'g'ri javob beradi (truthy/falsy).

3. Xususiyatlar: atributning JavaScript'dagi "egizagi"

3.1 Atribut va xususiyat

DOM daraxti darsidan bilasiz: har element — JavaScript obyekti. Obyektning esa xususiyatlari (properties) bor: element.id, element.title. Brauzer HTML'ni o'qiyotganda ko'p standart atributlar uchun shunday xususiyat yasaydi va ularni bog'lab qo'yadi. Biri o'zgarsa — ikkinchisi ham. Buni aks ettirish (reflection) deyishadi.

Hayotdan o'xshatish: choyxonaning menyu doskasi va oshxona. Doskada bo'r bilan yozilgan narx — atribut: hamma ko'radigan, HTML'dagi yozuv. Oshxonadagi kassa dasturidagi narx — xususiyat: dastur aynan shu bilan ishlaydi. Yaxshi choyxonada ikkalasi bir xil. Lekin ba'zan ular ajralib qoladi — buni «value tuzog'i» bo'limida ko'ramiz.

html
<a id="havola" href="https://example.com/menyu">Menyu</a>
<script>
  const havola = document.querySelector("#havola");
  console.log(havola.id, havola.getAttribute("id"));

  havola.id = "asosiy-menyu";
  console.log(havola.getAttribute("id"));

  havola.setAttribute("title", "Bugungi taomlar");
  console.log(havola.title);
  console.log(havola);
</script>

Konsolda:

text
havola havola
asosiy-menyu
Bugungi taomlar
<a id="asosiy-menyu" href="https://example.com/menyu" title="Bugungi taomlar">Menyu</a>

Xususiyatga yozdik — atribut o'zgardi. Atributga yozdik — xususiyat o'zgardi. Oddiy holatda ular aynan egizak.

3.2 Nomlari boshqacha bo'lganlar

Ikki atributning xususiyat nomi boshqacha, chunki class va for — JavaScript'ning kalit so'zlari:

Atribut (HTML) Xususiyat (JS) Nega
class className (yoki classList) class — kalit so'z
for (label da) htmlFor for — sikl kalit so'zi
aria-current ariaCurrent chiziqcha → camelCase
data-taom-raqami dataset.taomRaqami «dataset» bo'limida
html
<label id="yorliq" for="ism" class="majburiy">Ism</label>
<input id="ism">
<script>
  const yorliq = document.querySelector("#yorliq");
  console.log(yorliq.className, yorliq.htmlFor);
  console.log(yorliq.class, yorliq.for);
</script>

Konsolda:

text
majburiy ism
undefined undefined

yorliq.class — undefined: bunday xususiyat yo'q. Xato ham chiqmaydi — shuning uchun bu xato uzoq yashirinadi. class bilan ishlashning qulay usuli — classList — keyingi darsda (classList va stillar).

3.3 Xususiyat qiymatni "tozalab" beradi

Ba'zi xususiyatlar atributni shunchaki ko'chirmaydi — uni tayyor ko'rinishga keltiradi. Eng yaqqol misol — href:

html
<a id="h" href="HTTPS://Example.COM/menyu">Menyu</a>
<a id="b" href="https://example.com">Bosh sahifa</a>
<script>
  const h = document.querySelector("#h");
  console.log(h.getAttribute("href"));
  console.log(h.href);
  console.log(h.hostname, h.pathname);

  const b = document.querySelector("#b");
  console.log(b.getAttribute("href"), b.href);
</script>

Konsolda:

text
HTTPS://Example.COM/menyu
https://example.com/menyu
example.com /menyu
https://example.com https://example.com/

Atribut — siz yozgan matn, harfma-harf. Xususiyat — brauzer tushungan to'liq manzil: protokol va domen kichik harfga o'tdi, oxiriga / qo'shildi. Havolada hostname (domen) va pathname (yo'l) kabi qismlar ham bor — ular faqat xususiyat sifatida mavjud.

Nisbiy yo'lda farq yanada katta. Portfolio'ngizning aloqa/ sahifasida href="../loyihalar/" turgan havolani DevTools konsolida tekshirib ko'ring:

js
const h = document.querySelector('a[href="../loyihalar/"]');
h.getAttribute("href"); // "../loyihalar/" — yozilganidek
h.href;     // "http://127.0.0.1:5500/loyihalar/" — to'liq manzil
h.pathname; // "/loyihalar/"

Jonli oyna izolyatsiyalangan va o'z manzili yo'q, shuning uchun nisbiy yo'lni u to'liq manzilga aylantira olmaydi — bu misol faqat haqiqiy sahifada ishlaydi. Live Server bo'lmasa, manzil boshqacha bo'ladi.

Amaliy qoida: "HTML'da nima yozilgan?" — getAttribute. "Brauzer aslida qayerga boradi?" — xususiyat.

Tekshirib ko'ring: <a href="#menyu"> uchun getAttribute("href") va href xususiyati bir xil chiqadimi?

Javob

Yo'q. getAttribute("href") — "#menyu", yozilganidek. href xususiyati esa to'liq manzil: sahifaning o'z manzili + #menyu, masalan https://example.com/menyu/#menyu. Brauzer har doim to'liq manzilni beradi.

4. value tuzog'i: atribut — boshlang'ich, xususiyat — hozirgi

4.1 Foydalanuvchi yozganda nima bo'ladi

Endi «ajralib qolish» holati. Quyidagi oynada maydonda "Ali" turibdi. Uni o'chirib, o'z ismingizni yozing va Tekshirish tugmasini bosing. Tugma bosilganda kod ishlashi uchun addEventListener("click", ...) — O'tgan darsdagi qolip, to'liq — addEventListener asoslari darsida:

html
<label for="ism">Ism</label>
<input id="ism" value="Ali">
<button type="button" id="tekshir">Tekshirish</button>
<script>
  const ism = document.querySelector("#ism");
  console.log(ism.value, ism.getAttribute("value"));

  document.querySelector("#tekshir")
    .addEventListener("click", () => {
      console.log("xususiyat:", ism.value);
      console.log("atribut:", ism.getAttribute("value"));
    });
</script>

Konsolda:

text
Ali Ali

Sahifa ochilganda ikkalasi "Ali". Endi "Vali" deb yozib, tugmani bosing — konsolda xususiyat: Vali va atribut: Ali chiqadi. Maydonda yozilgan narsa — xususiyatda. Atribut esa HTML'da yozilgan boshlang'ich qiymat bo'lib qoldi.

Bu tasodif emas, qoida. value atributi — boshlang'ich qiymat (sukut bo'yicha). value xususiyati — hozirgi qiymat. Foydalanuvchi yozganda faqat xususiyat o'zgaradi. JavaScript'da ism.value = "..." yozsangiz ham — faqat xususiyat.

Atributni o'qishning xususiyat shakli ham bor — defaultValue. Diagrammada ikki qiymatning yo'li — chapdan o'ngga:

flowchart LR
  H["HTML: value=Ali"] --> A["value atributi = defaultValue"]
  A -->|"sahifa ochilganda bir marta"| X["value xususiyati"]
  F["Foydalanuvchi yozdi"] --> X
  J["JS: ism.value = ..."] --> X
  S["JS: setAttribute"] --> A
  X -.->|"qaytib yozilmaydi"| A

O'qlarga qarang: atributdan xususiyatga yo'l bor, teskarisiga — yo'q.

4.2 Atributni o'zgartirsa-chi?

Teskari yo'lni o'zingiz sinab ko'ring. Tugma atributga "Jasur" yozadi va ikkala qiymatni konsolga chiqaradi:

html
<label for="ism">Ism</label>
<input id="ism" value="Ali">
<button type="button" id="yoz">Atributga Jasur</button>
<script>
  const ism = document.querySelector("#ism");
  document.querySelector("#yoz")
    .addEventListener("click", () => {
      ism.setAttribute("value", "Jasur");
      console.log("maydonda:", ism.value);
      console.log("atribut:", ism.getAttribute("value"));
    });
</script>

Ikki bosqichda bosing:

  1. Maydonga tegmasdan tugmani bosing. Maydonda "Jasur" paydo bo'ladi, konsolda maydonda: Jasur va atribut: Jasur. Maydon hali "tegilmagan" — brauzer hozirgi qiymatni atributdan olib turibdi.
  2. Endi maydonni tozalab, "Vali" deb yozing va yana bosing. Konsolda maydonda: Vali va atribut: Jasur. Maydon endi "tegilgan" — brauzer hozirgi qiymatni atributdan olmay qo'ydi.

Qoida shu: foydalanuvchi yozgandan (yoki JavaScript ism.value = ... qilgandan) keyin atribut maydonni boshqarmaydi.

Atribut qachon kerak bo'ladi? Forma tozalanganda. <button type="reset"> (Tugmalar va yuborish) har maydonni atributidagi boshlang'ich qiymatga qaytaradi. Shuning uchun value atributini "tozalashda qaytadigan qiymat" deb tushuning.

Qoida: maydondagi hozirgi matnni o'qish va yozish — doim input.value. getAttribute("value") — faqat boshlang'ich qiymat kerak bo'lsa. Forma qiymatlari bilan ishlashni Forma qiymatlarini o'qish darsida to'liq ko'ramiz.

4.3 checked va indeterminate

Belgilash katagida (checkbox) xuddi shunday juftlik bor: checked atributi — boshlang'ich holat (defaultChecked), checked xususiyati — hozirgi holat.

Bitta holat esa faqat xususiyatda yashaydi — indeterminate (qisman belgilangan). Forma komponentlari darsida "Hamma taomlarni tanlash" katagini qisman holatda bezagan edik. O'shanda "holatni HTML atributi bilan emas, JavaScript xususiyati bilan qo'yamiz" degandik:

html
<label>
  <input type="checkbox" id="hammasi">
  Hamma taomlarni tanlash
</label>
<script>
  const hammasi = document.querySelector("#hammasi");
  hammasi.indeterminate = true;
  console.log(hammasi.indeterminate);
  console.log(hammasi.hasAttribute("indeterminate"));
  console.log(hammasi.matches(":indeterminate"));
</script>

Konsolda:

text
true
false
true

Natijada katak ichida chiziqcha. Atribut yo'q (false), lekin CSS'ning :indeterminate pseudo-klassi holatni ko'radi (matches shuni tasdiqladi). HTML'da indeterminate atributini yozib bo'lmaydi — bunday atribut standartda yo'q.

Tekshirib ko'ring: Foydalanuvchi telefon maydoniga +998 90 000 00 00 yozdi. Dasturchi uni getAttribute("value") bilan o'qib, bo'sh satr oldi. Nega?

Javob

HTML'da value atributi yozilmagan bo'lsa, getAttribute("value") — null; value="" bo'lsa — bo'sh satr. Foydalanuvchi yozgani esa atributga tushmaydi — faqat value xususiyatiga. To'g'ri o'qish: telefon.value.

5. Boolean atributlar: borligi — true

5.1 disabled="false" tuzog'i

disabled, hidden, checked, required, readonly — boolean (mantiqiy) atributlar (Maydon holatlari). Ular uchun qiymat ahamiyatsiz: atribut bor bo'lsa — yoqilgan, yo'q bo'lsa — o'chiq. Hatto disabled="false" ham tugmani o'chiradi:

html
<button id="bron" type="button" disabled="false">Bron</button>
<script>
  const bron = document.querySelector("#bron");
  console.log(bron.disabled);
  bron.setAttribute("disabled", false);
  console.log(bron.disabled, bron.getAttribute("disabled"));
</script>

Konsolda:

text
true
true false

Tugma kulrang — bosib bo'lmaydi. "false" — bu bo'sh bo'lmagan satr, brauzer uni "atribut bor" deb tushunadi. setAttribute("disabled", false) ham yordam bermadi: false satrga ("false") aylandi.

5.2 To'g'ri yo'l — xususiyat

Boolean atributlarning xususiyati haqiqiy true/false bilan ishlaydi — eng qulay yo'l shu:

html
<button id="bron" type="button" disabled>Stol band qilish</button>
<script>
  const bron = document.querySelector("#bron");
  bron.disabled = false;
  console.log(bron.hasAttribute("disabled"), bron);

  bron.hidden = true;
  console.log(bron);
  bron.hidden = false;
</script>

Konsolda:

text
false <button id="bron" type="button">Stol band qilish</button>
<button id="bron" type="button" hidden="">Stol band qilish</button>

bron.disabled = false — atribut butunlay olib tashlandi. bron.hidden = true — hidden="" qo'shildi. Xususiyat atributni o'zi boshqaradi.

Maqsad
Yoqish el.disabled = true yoki setAttribute("disabled", "") —
O'chirish el.disabled = false yoki removeAttribute("disabled") setAttribute("disabled", false)
Almashtirish el.toggleAttribute("disabled") —

6. aria-* atributlari — boolean emas!

Mana nozik joy. aria-invalid, aria-expanded, aria-current — ular boolean atribut emas. Ularda qiymat muhim: aria-invalid="false" — "xato yo'q" degani, aria-invalid="true" — "xato bor" (ARIA asoslari). Shuning uchun ular setAttribute bilan aniq satr qiymat oladi.

Atribut selektorlari darsidagi telefon maydonini endi JavaScript bilan ishlatamiz. Bo'sh joylarsiz 13 belgidan (+998 va 9 ta raqam) qisqa bo'lsa — xato. Maydonga raqam yozib, Tekshirish ni bosing:

html
<style>
  [aria-invalid="true"] {
    border: 2px solid #b4461a;
    outline-color: #b4461a;
  }
  #telefon-xato { color: #b4461a; }
</style>
<label for="telefon">Telefon raqamingiz</label>
<input id="telefon" type="tel" value="+998 90 12"
       aria-describedby="telefon-xato">
<button type="button" id="tekshir">Tekshirish</button>
<p id="telefon-xato"></p>
<script>
  const telefon = document.querySelector("#telefon");
  const xato = document.querySelector("#telefon-xato");

  function telefonniTekshir() {
    const raqam = telefon.value.replaceAll(" ", "");
    const togri = raqam.length >= 13;
    telefon.setAttribute("aria-invalid", String(!togri));
    xato.textContent = togri ? "" : "Xato: raqamni to'liq kiriting.";
    console.log(telefon.getAttribute("aria-invalid"));
  }

  telefonniTekshir();
  document.querySelector("#tekshir")
    .addEventListener("click", telefonniTekshir);
</script>

Konsolda:

text
true

Sahifa ochilganda raqam to'liq emas — maydon qizil ramkada, ostida xato matni. Maydonga to'liq raqam yozing (masalan +998 90 000 00 00) va tugmani bosing — konsolda false chiqadi, ramka va xato yo'qoladi.

Kodda uch narsa bor:

  • String(!togri) — true/false ni aniq "true"/"false" satriga aylantiradi (Turlarni aniq o'zgartirish). Natija bir xil bo'lardi, lekin kod nima qilayotgani ko'rinib turadi.
  • CSS [aria-invalid="true"] — qiymat bilan tanlaydi. Agar faqat [aria-invalid] yozilganda, "false" qiymatli maydon ham qizil bo'lardi — atribut bor-da.
  • Xato matni textContent bilan, aria-describedby orqali maydonga bog'langan: Malika NVDA bilan maydonga kelganda "invalid entry" va xato matnini eshitadi.

Haqiqiy forma tekshiruvini (har harf yozilganda, yuborishda) input va change va Constraint Validation API darslarida yozamiz. Bugun — faqat atribut qismi.

aria-* atributlarining ham xususiyat egizaklari bor: el.ariaCurrent, el.ariaInvalid, el.ariaExpanded. Ular 2023-yildan beri hamma asosiy brauzerda ishlaydi (Baseline). Lekin ular ham satr qaytaradi: el.ariaInvalid — "true", true emas. Ko'p jamoalar aniqlik uchun setAttribute ni afzal ko'radi — kurs ham shunday qiladi.

Tekshirib ko'ring: menyuTugma.setAttribute("aria-expanded", false) — xato bormi?

Javob

Bu holatda xato yo'q. aria-expanded boolean atribut emas, unga "false" satri kerak. setAttribute false ni "false" satriga aylantiradi — aynan kerakli qiymat. disabled bilan bunday yozish esa xato edi. Farq — atribut turida: boolean atributda borlik muhim, aria-* da qiymat.

7. data-* atributlari va dataset

7.1 O'qish

Global atributlar darsida taom kartasiga uchta data-* atribut yozgandik — ekranda ko'rinmaydigan, faqat dastur uchun ma'lumot. Ularning hammasi element.dataset obyektida jamlanadi:

html
<article class="taom-karta" data-taom-raqami="17"
         data-achchiq="2" data-porsiya="12">
  <h3>Lag'mon</h3>
</article>
<script>
  const karta = document.querySelector(".taom-karta");
  console.log(karta.dataset);
  console.log(karta.dataset.taomRaqami);
  console.log(karta.dataset.yoq);
</script>

Konsolda:

text
DOMStringMap {taomRaqami: '17', achchiq: '2', porsiya: '12'}
17
undefined

Nomga qarang: HTML'da data-taom-raqami, JavaScript'da taomRaqami. Qoida:

  • data- qismi tashlanadi;
  • har chiziqchadan keyingi harf katta bo'ladi, chiziqcha yo'qoladi (camelCase).

Chiziqcha JavaScript'da ayirish belgisi — karta.dataset.taom-raqami "taom minus raqami" deb o'qilardi. Shuning uchun nom o'zgaradi. Yo'q atribut — undefined (getAttribute dagi null emas).

7.2 Hamma qiymat — satr

dataset dagi hamma narsa satr. Hisoblashdan oldin songa aylantiring:

html
<article class="taom-karta" data-porsiya="12">
  <h3>Lag'mon</h3>
</article>
<script>
  const karta = document.querySelector(".taom-karta");
  console.log(karta.dataset.porsiya + 1);
  console.log(Number(karta.dataset.porsiya) + 1);
</script>

Konsolda:

text
121
13

"12" + 1 — satrlar birlashdi: "121" (Yashirin coercion). Number() bilan aylantirgandan keyingina haqiqiy qo'shish bo'ldi (Matn ↔ son).

7.3 Yozish va o'chirish

dataset ga yozish — atributni yozish, delete — o'chirish:

html
<article class="taom-karta" data-taom-raqami="17"
         data-achchiq="2" data-porsiya="12">
  <h3>Lag'mon</h3>
</article>
<script>
  const karta = document.querySelector(".taom-karta");
  karta.dataset.porsiya = Number(karta.dataset.porsiya) - 1;
  karta.dataset.tugashVaqti = "21:00";
  delete karta.dataset.achchiq;
  console.log(karta.getAttribute("data-porsiya"));
  console.log(karta.getAttribute("data-tugash-vaqti"));
  console.log("achchiq" in karta.dataset);
</script>

Konsolda:

text
11
21:00
false

tugashVaqti HTML'ga teskari yo'l bilan tushdi: katta harf → chiziqcha + kichik harf, oldiga data-. "achchiq" in karta.dataset — in operatori: "shunday kalit bormi?"

7.4 JavaScript yozadi — CSS chizadi

data-* ning eng kuchli tomoni — CSS ularni atribut selektorlari bilan ko'radi. JavaScript faqat ma'lumotni o'zgartiradi, ko'rinishni CSS hal qiladi. Quyidagi oynada Achchiqroq ni bir necha marta bosing:

html
<style>
  .taom-karta { padding: 8px; border: 3px solid #c9d6cf; }
  [data-achchiq="1"] { border-color: #e9b38f; }
  [data-achchiq="2"] { border-color: #d9773f; }
  [data-achchiq="3"] { border-color: #b4461a; }
</style>
<article class="taom-karta" data-achchiq="0">
  <h3>Lag'mon</h3>
  <p>Achchiqlik: <span class="daraja">0</span></p>
</article>
<button type="button">Achchiqroq</button>
<script>
  const karta = document.querySelector(".taom-karta");
  const daraja = karta.querySelector(".daraja");

  document.querySelector("button")
    .addEventListener("click", () => {
      let yangi = Number(karta.dataset.achchiq) + 1;
      if (yangi > 3) {
        yangi = 0;
      }
      karta.dataset.achchiq = yangi;
      daraja.textContent = yangi;
      console.log(karta.dataset);
    });
</script>

Har bosishda ramka rangi to'qlashadi: 1, 2, 3, keyin yana 0 ga qaytadi. Konsolda har safar DOMStringMap {achchiq: '1'} kabi qator chiqadi. JavaScript kodida bitta ham rang yo'q — dizayner Nodira ranglarni o'zgartirmoqchi bo'lsa, faqat CSS'ga tegadi.

7.5 data-* mi, class mi, oddiy atributmi?

Nima saqlanadi Nima ishlatiladi Misol
Standart ma'noli holat O'sha standart atribut disabled, hidden, aria-invalid, aria-current
Faqat ko'rinish ("qizil", "katta") class (keyingi dars) taom-karta yangi
Dastur uchun ma'lumot, qiymat bilan data-* data-taom-raqami="17"

Birinchi qatorni unutmang: standart atribut bo'lsa, data-* o'ylab topilmaydi. data-xato="ha" emas — aria-invalid="true": u ekran o'quvchiga ham ishlaydi.

data-* ning yana bir keng tarqalgan ishlatilishi — avtomatik testlar. CSS Modules darsida aytilgandek, testlar elementni o'zgaruvchan class bo'yicha emas, data-testid="savat-tugma" kabi barqaror atribut bo'yicha topadi. Testlarni kursda alohida o'rganamiz.

Tekshirib ko'ring: <div data-Narx="5000"> — dataset da kalit qanday nomlanadi?

Javob

narx. HTML atribut nomlari kichik harfga aylantiriladi, shuning uchun data-Narx aslida data-narx. Katta harf kerak bo'lsa (dataset.taomNarxi), HTML'da chiziqcha yoziladi: data-taom-narxi. Shuning uchun data-* nomlarini doim kichik harf va chiziqcha bilan yozing (Global atributlar darsidagi qoida).

8. Ko'p uchraydigan xatolar

8.1 Hozirgi qiymatni getAttribute("value") bilan o'qish

Foydalanuvchi yozgani u yerda yo'q. Tuzatish: input.value.

8.2 setAttribute("disabled", false)

Tugma baribir o'chiq qoladi («Boolean atributlar» bo'limi). Tuzatish: el.disabled = false yoki removeAttribute("disabled").

8.3 dataset dagi qiymatni son deb hisoblash

dataset.porsiya + 1 → "121". Tuzatish: Number(dataset.porsiya) + 1.

8.4 Chiziqchali nom bilan dataset ga murojaat

html
<article data-taom-raqami="17"><h3>Lag'mon</h3></article>
<script>
  const karta = document.querySelector("article");
  console.log(karta.dataset["taom-raqami"]);
  console.log(karta.dataset.taomRaqami);
</script>

Konsolda:

text
undefined
17

Kvadrat qavsda ham camelCase nomi kerak: dataset["taomRaqami"]. Chiziqchali nom — faqat getAttribute("data-taom-raqami") da.

8.5 Mavjud bo'lmagan xususiyatga yozish

el.class = "yangi" — xato chiqmaydi, lekin atribut o'zgarmaydi: siz obyektga yangi, hech narsaga bog'lanmagan kalit qo'shdingiz. O'zingiz o'ylab topgan nomlar ham shunday: karta.achchiq = 3 HTML'ga tushmaydi. Tuzatish: className/classList, dataset.achchiq yoki setAttribute.

9. Mashqlar

1-mashq (oson): Havolani tekshiring

Har havola uchun konsolga chiqaring: matni va target atributi bormi. Kutilgan natija:

text
Menyu false
Instagram true
html
<a href="https://example.com/menyu">Menyu</a>
<a href="https://example.com/ig" target="_blank">Instagram</a>
<script>
  // shu yerga yozing
</script>
Yechim
html
<a href="https://example.com/menyu">Menyu</a>
<a href="https://example.com/ig" target="_blank">Instagram</a>
<script>
  for (const havola of document.querySelectorAll("a")) {
    console.log(havola.textContent, havola.hasAttribute("target"));
  }
</script>

Konsolda:

text
Menyu false
Instagram true

target="_blank" li havola yangi tabda ochiladi. Bunday havolalarni topish real auditda foydali: ularga ko'pincha "yangi tabda ochiladi" degan yashirin izoh kerak (Maxsus havolalar va rel).

2-mashq (o'rta): Porsiya tugadi

Har karta uchun data-porsiya ni o'qing. Porsiya 0 bo'lsa — kartaga data-tugadi atributini qo'ying (qiymatsiz) va konsolga Tugadi: <taom nomi> chiqaring. Oxirida tugagan taomlar sonini chiqaring. CSS tayyor: data-tugadi li karta xiralashadi.

Ishora: Number() bilan songa aylantiring; atributni qiymatsiz qo'yish — toggleAttribute(nom, true); taom nomi — kartadagi h3.

html
<style>
  [data-tugadi] { opacity: 0.4; }
</style>
<article class="taom-karta" data-porsiya="12">
  <h3>Osh</h3>
</article>
<article class="taom-karta" data-porsiya="0">
  <h3>Manti</h3>
</article>
<article class="taom-karta" data-porsiya="0">
  <h3>Lag'mon</h3>
</article>
<script>
  // shu yerga yozing
</script>
Yechim
html
<style>
  [data-tugadi] { opacity: 0.4; }
</style>
<article class="taom-karta" data-porsiya="12">
  <h3>Osh</h3>
</article>
<article class="taom-karta" data-porsiya="0">
  <h3>Manti</h3>
</article>
<article class="taom-karta" data-porsiya="0">
  <h3>Lag'mon</h3>
</article>
<script>
  let tugagan = 0;
  for (const karta of document.querySelectorAll(".taom-karta")) {
    const porsiya = Number(karta.dataset.porsiya);
    if (porsiya === 0) {
      karta.toggleAttribute("data-tugadi", true);
      console.log(`Tugadi: ${karta.querySelector("h3").textContent}`);
      tugagan++;
    }
  }
  console.log(`Jami tugagan: ${tugagan}`);
</script>

Konsolda:

text
Tugadi: Manti
Tugadi: Lag'mon
Jami tugagan: 2

karta.dataset.tugadi = "" ham xuddi shu atributni qo'yadi. Number() siz "0" === 0 hech qachon true bo'lmasdi — satr va son. «Bahor»da bu holat uchun tugadi class'i ham bor — class bilan qilishni keyingi darsda ko'ramiz.

3-mashq (qiyin): Atributlar hisoboti

Har maydon uchun bitta qator chiqaring: id, majburiymi (required — xususiyat bilan) va boshlang'ich qiymati (value atributi; bo'lmasa —). Keyin JavaScript bilan ism maydoniga "Aziz" yozing va yana bir qator chiqaring: hozirgi qiymat va boshlang'ich qiymat. Kutilgan natija:

text
ism majburiy: true boshlang'ich: —
telefon majburiy: false boshlang'ich: +998
Hozir: Aziz | boshlang'ich: —

Ishora: getAttribute yo'q atributda null beradi — ?? bilan "—" ga almashtiring (??).

html
<label for="ism">Ism</label>
<input id="ism" required>
<label for="telefon">Telefon</label>
<input id="telefon" type="tel" value="+998">
<script>
  // shu yerga yozing
</script>
Yechim
html
<label for="ism">Ism</label>
<input id="ism" required>
<label for="telefon">Telefon</label>
<input id="telefon" type="tel" value="+998">
<script>
  for (const maydon of document.querySelectorAll("input")) {
    const boshlangich = maydon.getAttribute("value") ?? "—";
    console.log(
      `${maydon.id} majburiy: ${maydon.required}`,
      `boshlang'ich: ${boshlangich}`,
    );
  }
  const ism = document.querySelector("#ism");
  ism.value = "Aziz";
  const asli = ism.getAttribute("value") ?? "—";
  console.log(`Hozir: ${ism.value} | boshlang'ich: ${asli}`);
</script>

Konsolda:

text
ism majburiy: true boshlang'ich: —
telefon majburiy: false boshlang'ich: +998
Hozir: Aziz | boshlang'ich: —

maydon.required — boolean xususiyat, haqiqiy true/false. getAttribute("required") esa "" yoki null qaytarardi. JavaScript'dan value ga yozish ham atributni o'zgartirmadi — «value tuzog'i» bo'limidagi qoida.

4-mashq: Portfolio qadami — joriy sahifa havolasi

Portfolio menyusidagi aria-current="page" ni 04-qismda har sahifaga qo'lda yozgansiz. Yangi sahifa qo'shilganda uni unutish oson. O'tgan darsdan oldingi menyuniTop funksiyasi joriy havolani faqat o'qigan edi. Endi joriyHavolaniBelgila funksiyasi uni tekshirsin va tuzatsin:

  1. Menyuni toping; 404.html da u yo'q — jim tugasin.
  2. Har havola uchun solishtiring: havolaning pathname xususiyati sahifaning manzili location.pathname ga tengmi (Brauzer muhiti darsidagi BOM). Bosh sahifa ba'zan /index.html, ba'zan / bo'lib ochiladi — ikkala yo'ldan oxiridagi index.html ni olib tashlab solishtiring (endsWith, slice — Matn ichida qidirish, Kesish).
  3. Mos havolada aria-current bo'lmasa — console.warn bilan ogohlantirib, qo'ying. Mos bo'lmagan havolada bo'lsa — ogohlantirib, olib tashlang.
  4. Qo'shimcha: <html> ga data-js atributini qo'ying (dataset bilan). Bu "JavaScript ishladi" degan belgi — keyingi darslarda faqat JavaScript bilan ishlaydigan tugmalarni (tema, mobil menyu) CSS shunga qarab ko'rsatadi.

Commit: JS: joriy sahifa havolasini avtomatik belgila.

Yechim

asosiy.js ga (menyuniTop dan keyin):

js
function yolniTozala(yol) {
  if (yol.endsWith("index.html")) {
    return yol.slice(0, -"index.html".length);
  }
  return yol;
}

function joriyHavolaniBelgila() {
  const menyu = document.querySelector(
    'nav[aria-label="Asosiy menyu"]',
  );
  if (menyu === null) {
    return;
  }
  const joriyYol = yolniTozala(location.pathname);
  for (const havola of menyu.querySelectorAll("a")) {
    const mos = yolniTozala(havola.pathname) === joriyYol;
    const belgili = havola.hasAttribute("aria-current");
    if (mos && !belgili) {
      console.warn(`aria-current yo'q: ${havola.textContent}`);
      havola.setAttribute("aria-current", "page");
    } else if (!mos && belgili) {
      console.warn(`Ortiqcha aria-current: ${havola.textContent}`);
      havola.removeAttribute("aria-current");
    }
  }
}

document.documentElement.dataset.js = "bor";
joriyHavolaniBelgila();

Nega getAttribute("href") emas, pathname xususiyati? HTML'da bosh sahifaga ../, ./ yoki ../../ yozilgan — sahifaga qarab har xil. Xususiyat esa brauzer hisoblagan to'liq yo'lni beradi, uni sahifa manzili bilan to'g'ridan-to'g'ri solishtirsa bo'ladi.

Sinov: Live Server bilan aloqa/ sahifasini oching va DevTools → Elements'da aria-current ni qo'lda boshqa havolaga ko'chiring. Sahifani yangilasangiz — HTML'dagi asl holat qaytadi, shuning uchun sinovni HTML faylda qiling: bitta sahifada aria-current ni ataylab noto'g'ri havolaga yozing. Konsolda ikki sariq ogohlantirish chiqadi, Elements panelida esa belgi to'g'ri havolada turadi. Keyin HTML'ni tuzatib qo'ying — ogohlantirish yo'qolishi kerak. Elements'da <html ... data-js="bor"> ni ham ko'rasiz.

aria-current ni HTML'dan olib tashlamang: JavaScript ishlamasa ham Malika joriy sahifani eshitishi kerak. JavaScript — faqat tekshiruvchi va zaxira.

10. Real ishda

  • Forma tekshiruvi — aria-invalid, aria-describedby, disabled ni JavaScript qo'yadi. Ularni noto'g'ri qo'yish (disabled="false") — real loyihalardagi tez-tez uchraydigan xato.
  • data-* — HTML va JavaScript orasidagi ko'prik. Server sahifani chizganda kartaga data-taom-raqami yozadi, JavaScript esa "savatga qo'shish" bosilganda shu raqamni serverga yuboradi (fetch).
  • Testlar elementni data-testid bo'yicha topadi — dizayn o'zgarsa ham test buzilmaydi.
  • Freymvorklarda (React — kursda alohida o'rganamiz) ham shu farq bor: React'da value va defaultValue alohida — bugungi "boshlang'ich va hozirgi qiymat" g'oyasining o'zi.
  • Intervyuda so'raladi: "Atribut va xususiyat (property) farqi nima?" Eng yaxshi javob — value misoli bilan.

Xulosa

  • Atribut — HTML'dagi yozuv (getAttribute/setAttribute/hasAttribute/removeAttribute/toggleAttribute); xususiyat — obyektdagi jonli qiymat.
  • Ko'p atributlar xususiyat bilan aks etadi, ba'zilari boshqa nomda: className, htmlFor; href xususiyati — to'liq manzil.
  • value/checked atributi — boshlang'ich qiymat; xususiyat — hozirgi. Foydalanuvchi faqat xususiyatni o'zgartiradi.
  • Boolean atributda borlik muhim (disabled="false" ham o'chiradi) — xususiyat bilan boshqaring; aria-* da esa qiymat muhim.
  • data-taom-raqami → dataset.taomRaqami; qiymatlar doim satr; CSS ularni atribut selektori bilan ko'radi.

Keyingi dars: classList va stillarni JS'dan boshqarish — class'larni qo'shish va olib tashlash, inline stil, CSS o'zgaruvchilari va getComputedStyle.

Manbalar

  • MDN: "Element: getAttribute() method", "Element: toggleAttribute() method", "HTMLElement: dataset property" — developer.mozilla.org
  • MDN: "HTML attribute reference: Boolean attributes", "Attribute reflection" — developer.mozilla.org
  • HTML Standard: "Reflecting content attributes in IDL attributes" — html.spec.whatwg.org
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
HTML atributlari JavaScript'da: getAttribute, setAttribute, xususiyatlar va dataset — IlmHamroh