IlmHamroh
JavaScript Full-stack/9-qism. JavaScript brauzerda va debugging2/29-dars19 daqiqa
Mundarija (33)

DOM daraxti: tugun turlari va Node → Element → HTMLElement ierarxiyasi

Qisqacha: DOM — brauzer HTML'dan quradigan obyektlar daraxti. Undagi har bir qism tugun (node): teglar — element tugunlari, ular orasidagi matn va hatto bo'sh joylar — matn tugunlari, <!-- --> — izoh tugunlari, eng tepada esa document. Har tugun turi nodeType raqami bilan ajraladi va o'z "oilasidan" imkoniyat oladi: Node → Element → HTMLElement → HTMLLIElement.

Bu darsda

  • HTML qanday qilib tugunlar daraxtiga aylanishini chizib bera olasiz.
  • Element, matn, izoh va document tugunlarini nodeType va nodeName bilan ajrata olasiz.
  • Nega childNodes da kutilmagan "bo'sh" tugunlar borligini tushuntira olasiz.
  • Node → Element → HTMLElement ierarxiyasi qaysi xususiyat qayerdan kelishini belgilashini bilasiz.
  • DevTools Elements paneli va $0 bilan jonli DOM'ni o'rgana olasiz.

Oldin bilishingiz kerak: Brauzer muhiti: window, document va skript yuklanishi, Critical Rendering Path, DevTools I: Elements va Console.

1. Nega bu kerak?

O'tgan darsda JavaScript sarlavhani "Menyu" dan "Bugungi menyu" ga almashtirdi. HTML faylga esa tegmadi. Unda nima o'zgardi?

O'zgargani — brauzer xotirasidagi DOM. Critical Rendering Path darsida ko'rgandingiz: brauzer HTML matnini o'qib, undan daraxt quradi va ekranga aynan shu daraxtni chizadi. HTML fayl — faqat "qurilish chizmasi". Brauzer uni o'qib bo'lgach, chizmaga qaytmaydi — daraxt bilan ishlaydi.

JavaScript ham faqat daraxt bilan gaplashadi. Shuning uchun sahifani o'zgartirishni o'rganishdan oldin daraxt qanday tuzilganini bilish kerak. Aks holda null, undefined va "nega bu yerda yana bitta element bor?" degan savollar har qadamda chiqadi.

2. HTML'dan daraxtga

2.1 Kichik menyu va uning daraxti

«Bahor» menyusidan bir parcha:

html
<ul id="menyu">
  <!-- narxlar so'mda -->
  <li class="taom">Osh</li>
  <li>Manti</li>
</ul>

Brauzer bu to'rt qatordan quyidagi daraxtni quradi. Kulrang tugunlar — teglar orasidagi bo'sh joylar. Ular ham daraxtda bor, birozdan keyin sababini ko'ramiz:

flowchart TD
  UL["ul#menyu (element)"]
  T1["#text: Enter + bo'sh joy"]
  C["#comment: narxlar so'mda"]
  T2["#text"]
  LI1["li.taom (element)"]
  T3["#text"]
  LI2["li (element)"]
  T4["#text"]
  O["#text: Osh"]
  M["#text: Manti"]
  UL --> T1 & C & T2 & LI1 & T3 & LI2 & T4
  LI1 --> O
  LI2 --> M
  classDef bosh fill:#f1f1f1,stroke:#999,color:#555
  class T1,T2,T3,T4 bosh

Daraxtning har bir qismi — tugun (node). Tugun — DOM'dagi bitta obyekt: teg, matn bo'lagi yoki izoh.

Tugunlar orasidagi munosabatlar oila shajarasi so'zlari bilan ataladi:

  • Ota (parent) — bevosita o'rab turgan tugun. li ning otasi — ul.
  • Bola (child) — bevosita ichidagi tugun. "Osh" matni — birinchi li ning bolasi.
  • Aka-uka (sibling) — bir otaning bolalari. Ikki li — aka-uka.
  • Ildiz (root) — eng tepadagi, otasi yo'q tugun. Butun sahifada bu document.

Kompyuter daraxti teskari o'sadi: ildizi tepada, shoxlari pastda. Bu fayl tizimidagi papkalar daraxti bilan bir xil (Fayl tizimi).

2.2 Har teg — element, har matn — alohida tugun

Diagrammadagi muhim narsa: "Osh" so'zi li ning ichida emas, o'z tugunida turadi. li — element tugun, "Osh" — uning bolasi bo'lgan matn tuguni. Bu farq keyingi darslarda katta ahamiyatga ega: element bilan uning matni — ikki xil obyekt.

Xuddi shunday, <!-- narxlar so'mda --> izohi ham yo'qolib ketmaydi — u ham tugun. Ekranda ko'rinmaydi, lekin DOM'da bor.

Tekshirib ko'ring: <p>Osh <b>35 000</b> so'm</p> da nechta tugun bor (p ning o'zi bilan birga)?

Javob

Beshta. p (element) va uning uch bolasi: "Osh " (matn), b (element), " so'm" (matn). b ning ichida yana bitta tugun — "35 000" matni. Jami: p, b — ikkita element, uchta matn tuguni.

3. Tugun turlari: nodeType va nodeName

3.1 Daraxtni konsolda "tekshiramiz"

Har tugunning ikki "pasport" xususiyati bor:

  • nodeType — tugun turi, son bilan.
  • nodeName — tugun nomi, satr bilan. Element uchun — teg nomi katta harfda, boshqalar uchun # bilan boshlanadigan nom.

childNodes — tugunning barcha bolalari ro'yxati. U massivga o'xshaydi: .length bor va for...of bilan aylanib chiqsa bo'ladi. Diagrammadagi menyuni konsolda tekshiramiz:

html
<ul id="menyu">
  <!-- narxlar so'mda -->
  <li class="taom">Osh</li>
  <li>Manti</li>
</ul>
<script>
  const menyu = document.querySelector("#menyu");
  console.log(menyu.childNodes.length);
  for (const tugun of menyu.childNodes) {
    console.log(tugun.nodeType, tugun.nodeName);
  }
</script>

Konsolda:

text
7
3 #text
8 #comment
3 #text
1 LI
3 #text
1 LI
3 #text

Yetti tugun — diagrammadagidek. Ikki li dan tashqari to'rtta #text va bitta #comment.

3.2 Turlar jadvali

nodeType Turi nodeName Misol
1 Element teg nomi: LI, UL <li>Osh</li>
3 Matn (text) #text "Osh", bo'sh joylar
8 Izoh (comment) #comment <!-- ... -->
9 Hujjat (document) #document document ning o'zi
10 Hujjat turi (doctype) html <!DOCTYPE html>

Kundalik ishda faqat 1 va 3 tez-tez kerak bo'ladi. Raqamlarni yodlash shart emas: brauzerda ularning tayyor nomlari bor (qiymati o'zgarmaydigan, const ga o'xshash) — Node.ELEMENT_NODE (1), Node.TEXT_NODE (3), Node.COMMENT_NODE (8). Kodda tugun.nodeType === Node.ELEMENT_NODE yozish === 1 dan tushunarliroq.

Yana bitta tur bor — DocumentFragment (11). Bu ko'p elementni bir martada qo'shish uchun "vaqtinchalik quti", uni Ko'p elementni samarali chizish darsida ko'ramiz.

3.3 Bo'sh matn tugunlari qayerdan keldi?

HTML'ni chiroyli yozish uchun biz <ul> dan keyin Enter bosib, <li> ni ikki bo'sh joy bilan surdik. Brauzer uchun Enter va bo'sh joy — oddiy belgilar. Ular teglar orasida turgani uchun matn tuguniga aylanadi.

Bu matnni ko'rish uchun nodeValue dan foydalanamiz — matn tugunining ichidagi satr. Uni JSON.stringify bilan chiqaramiz: shunda Enter \n bo'lib ko'rinadi (JSON asoslari kursda keyinroq; hozir bu shunchaki "ko'rinmas belgilarni ko'rsatish" usuli):

html
<ul id="menyu">
  <li>Osh</li>
</ul>
<script>
  const menyu = document.querySelector("#menyu");
  for (const tugun of menyu.childNodes) {
    console.log(tugun.nodeName, JSON.stringify(tugun.nodeValue));
  }
</script>

Konsolda:

text
#text "\n  "
LI null
#text "\n"

Birinchi matn tuguni — Enter va ikki bo'sh joy. Element tugunining nodeValue si doim null: elementning "o'z matni" yo'q, matn uning bola tugunlarida.

Bo'sh joylar darsida ko'rgandingiz: brauzer ekranda bunday bo'sh joylarni bitta probelga qisqartiradi yoki umuman ko'rsatmaydi. Lekin DOM'da ular saqlanadi. Ko'zga ko'rinmagani bilan, childNodes ularni sanaydi.

3.4 childNodes va children

Faqat elementlar kerak bo'lsa, children bor — u matn va izoh tugunlarini tashlab ketadi:

html
<ul id="menyu">
  <!-- narxlar so'mda -->
  <li class="taom">Osh</li>
  <li>Manti</li>
</ul>
<script>
  const menyu = document.querySelector("#menyu");
  console.log(menyu.childNodes.length, menyu.children.length);
  console.log(menyu.children);
</script>

Konsolda:

text
7 2
HTMLCollection(2) [li.taom, li]

HTMLCollection(2) — "ikki elementli to'plam". Ichida li.taom — "taom class'li li" degan qisqa yozuv, CSS selektoriga o'xshaydi. Bu to'plam turini Elementlarni tanlash darsida batafsil ko'ramiz, ota-bola bo'ylab yurishni esa DOM bo'ylab harakatlanish darsida.

Maslahat: Amalda 90% holatda sizga children kerak. childNodes — matn tugunlari bilan ishlash yoki "nega sanoq to'g'ri chiqmayapti?" degan savolga javob izlaganda.

Tekshirib ko'ring: <p>Salom</p> bitta qatorda yozilgan. p.childNodes.length va p.children.length nechaga teng?

Javob

childNodes.length — 1 (bitta matn tuguni "Salom"). children.length — 0, chunki p ichida birorta ham element yo'q. Matn — bola tugun, lekin bola element emas.

3.5 Atributlar va <script> — ular ham daraxtdami?

Ikki savol tez-tez tug'iladi.

Atributlar (id="menyu", class="taom") — bola tugun emas. Ular elementning "yorlig'i" sifatida elementning o'zida saqlanadi. Shuning uchun childNodes da atribut hech qachon chiqmaydi. Jadvalda 2-raqam yo'qligining sababi shu: eski standartda atribut tuguni (nodeType 2) bor edi, lekin u daraxtga kirmaydi va bugun deyarli ishlatilmaydi. Atributlar bilan ishlash — Atributlar, xususiyatlar va dataset darsida.

<script> tegi esa oddiy element — u ham daraxtda. Shuning uchun jonli oynalardagi document.body.children ro'yxatida oxirida SCRIPT ham chiqadi: skript o'zini ham "ko'radi". <style> va <head> dagi <meta> lar ham shunday — ekranda ko'rinmasa ham, DOM'da bor.

Qisqasi: daraxtda HTML'da yozilgan hamma narsa bor — teglar, matn, bo'sh joylar, izohlar. Faqat atributlar elementning ichki ma'lumoti sifatida alohida turadi.

4. document — daraxtning ildizi

document ham tugun, faqat maxsus: nodeType — 9, nodeName — #document. Uning bolalari — <!DOCTYPE html> (hujjat turi tuguni) va <html> elementi. <html> ichida esa head va body:

html
<!DOCTYPE html>
<html lang="uz">
<head>
  <meta charset="utf-8">
  <title>Menyu</title>
</head>
<body>
  <h1>Menyu</h1>
  <script>
    console.log(document.nodeType, document.nodeName);
    console.log(document.doctype.nodeType, document.doctype.nodeName);
    console.log(document.documentElement.nodeName);
    console.log(document.body.parentNode.nodeName);
  </script>
</body>
</html>

Konsolda:

text
9 #document
10 html
HTML
HTML

Oxirgi qatorda yangi xususiyat: parentNode — tugunning otasi. body ning otasi — html. O'tgan darsda ko'rgan document.documentElement, document.head, document.body — daraxtning eng ko'p kerak bo'ladigan tugunlariga tayyor "yorliq"lar.

Tekshirib ko'ring: document.documentElement.parentNode.nodeName nima qaytaradi? <html> ning otasi kim?

Javob

"#document". <html> — eng tepadagi element, lekin daraxtning ildizi emas. Uning otasi — document tugunining o'zi. document ning otasi esa yo'q: document.parentNode — null. Ildiz shunday bo'ladi.

5. Tugun "oilalari": Node → Element → HTMLElement

5.1 Nega hamma tugunda bir xil imkoniyat yo'q?

Elementda id bor, matn tugunida yo'q. <input> da value bor, <li> da value umuman boshqa ma'noda. <a> da href bor. Qaysi tugunda nima borligini kim belgilaydi?

Javob — ierarxiya. DOM'dagi har obyekt bir nechta "oila"ga tegishli. Har oila o'z imkoniyatlarini beradi, pastdagi oila esa yuqoridagilarnikini meros (inheritance) qilib oladi — ota-onadan bolaga o'tgandek.

Hayotdan o'xshatish: transport. Har qanday transport (yuradi) → avtomobil (rul, g'ildirak) → yengil avtomobil (5 o'rindiq) → Cobalt. Cobalt'da "yuradi", "rul" va "5 o'rindiq" ham bor — u hammasini yuqoridan oladi va o'zinikini qo'shadi.

flowchart TD
  ET["EventTarget: hodisalar"]
  N["Node: har qanday tugun"]
  E["Element: teg"]
  HE["HTMLElement: HTML tegi"]
  LI["HTMLLIElement: li"]
  A["HTMLAnchorElement: a"]
  IN["HTMLInputElement: input"]
  SVG["SVGElement: svg ichi"]
  CD["CharacterData"]
  T["Text"]
  C["Comment"]
  D["Document"]
  ET --> N
  N --> E & CD & D
  E --> HE & SVG
  HE --> LI & A & IN
  CD --> T & C

Diagrammani yuqoridan o'qing:

Daraja Kimlar Nima beradi (misollar)
EventTarget Hamma tugun va window Hodisalarni tinglash: addEventListener
Node Har qanday tugun nodeType, nodeName, childNodes, parentNode, textContent
Element Har qanday teg (HTML, SVG) id, children, querySelector, closest
HTMLElement Faqat HTML teglar hidden, title, lang, style, click()

Eng pastki darajada esa har tegning o'z "oilasi": HTMLInputElement da value va checked, HTMLAnchorElement da href.

5.2 instanceof bilan tekshiramiz

instanceof — "shu oilaga tegishlimi?" deb so'raydigan operator: x instanceof Element — x element bo'lsa true. U klasslar va prototiplar bilan bog'liq, ularni keyingi qismda chuqur o'rganamiz. Hozir uni shunchaki savol sifatida ishlating. Misolda yana bitta yangi xususiyat bor — firstChild: tugunning birinchi bola tuguni.

html
<ul>
  <li>Osh</li>
</ul>
<script>
  const li = document.querySelector("li");
  console.log(li instanceof HTMLLIElement, li instanceof HTMLElement);
  console.log(li instanceof Element, li instanceof Node);

  const matn = li.firstChild;
  console.log(matn.nodeName, matn instanceof Element);
  console.log(matn instanceof Node);
</script>

Konsolda:

text
true true
true true
#text false
true

li — to'rt oilaning hammasiga tegishli: eng aniqdan eng umumiygacha. li.firstChild — uning birinchi bolasi, bu yerda "Osh" matni. U Node, lekin Element emas. Shuning uchun matn tugunida querySelector yoki id ni qidirish befoyda — u bunday oiladan emas.

5.3 SVG istisnosi

Sahifadagi ikonkalar ko'pincha <svg> bilan chiziladi. SVG ichidagi teglar — element, lekin HTML elementi emas:

html
<svg width="40" height="40" aria-hidden="true">
  <circle cx="20" cy="20" r="18" fill="#2f6b3a"></circle>
</svg>
<script>
  const doira = document.querySelector("circle");
  console.log(doira instanceof Element, doira instanceof HTMLElement);
  console.log(doira.constructor.name);
</script>

Konsolda:

text
true false
SVGCircleElement

constructor.name — obyekt qaysi oila "nusxasi" ekanining nomi. Doira — SVGCircleElement. Amaliy xulosa: Element darajasidagi narsalar (id, querySelector, closest) SVG'da ham ishlaydi, HTMLElement dagilar (masalan hidden xususiyati) esa kafolatlanmagan.

Tekshirib ko'ring: textContent qaysi darajada e'lon qilingan? Demak, u matn tugunida ham ishlaydimi?

Javob

Node darajasida. Matn tuguni ham Node, shuning uchun unda ham textContent bor — u shu tugunning matnini beradi. id esa Element da, matn tugunida yo'q.

6. DOM — manba kodi emas

6.1 Brauzer HTML'ni "tuzatadi"

HTML'da xato bo'lsa, brauzer to'xtamaydi — DOM'ni o'zi to'g'rilab quradi (HTML'ni validatsiya qilish darsida bu "kechirimlilik"ni ko'rgansiz). Natijada DOM siz yozgan matndan farq qilishi mumkin:

html
<table>
  <tr><td>Osh</td><td>35 000</td></tr>
</table>
<p>Birinchi <div>ichki blok</div> oxiri</p>
<script>
  console.log(document.querySelector("tbody"));
  for (const el of document.body.children) {
    console.log(el.nodeName);
  }
</script>

Konsolda:

text
<tbody>…</tbody>
TABLE
P
DIV
P
SCRIPT

Ikki ajablanarli narsa:

  • tbody paydo bo'ldi. Biz uni yozmadik, lekin jadval qatorlari doim tbody (yoki thead, tfoot) ichida turishi kerak — brauzer qo'shib qo'ydi.
  • Bitta p ikkiga bo'lindi. p ichida div bo'la olmaydi. Brauzer div dan oldin p ni yopdi, </p> ni esa yangi, bo'sh p deb tushundi.

Bu nega muhim? Siz table > tr selektorini yozasiz — u ishlamaydi, chunki DOM'da tr ning otasi tbody. Xato HTML'ni yozgan joyda emas, DOM'da qidiriladi.

6.2 "Sahifa manbasi" va Elements paneli

Brauzerda ikki xil "kod" ko'rasiz:

Qayerda Nima ko'rinadi
Sahifa manbasi (Ctrl+U) Server yuborgan HTML matni — o'zgarmaydi
Elements paneli (F12) Jonli DOM — brauzer tuzatgan va JavaScript o'zgartirgan holat

JavaScript qo'shgan narsani Ctrl+U da qidirsangiz — topolmaysiz. Elements panelida esa u darhol ko'rinadi: o'zgargan tugun bir lahza binafsha rangda yonib o'chadi.

Hayotdan o'xshatish: choyxonaning qurilish loyihasi va choyxonaning bugungi holati. Loyihada (manba kodi) zalda 10 ta stol chizilgan. Bugun esa Jasur aka ikki stolni birlashtirdi, bittasini hovliga chiqardi. Mehmonga qaysi stol bo'shligini aytish uchun loyihaga emas, zalga (DOM'ga) qaraysiz.

Tekshirib ko'ring: HTML'da <ul> ichida <li> lar o'rniga to'g'ridan-to'g'ri <p> yozilgan. Ekranda hammasi joyida ko'rinadi. Brauzer bu p larni o'chirib tashlaydimi?

Javob

Yo'q. Brauzer faqat tuzilishni buzadigan holatlarda aralashadi: p ichidagi div, tr atrofidagi tbody. ul > p noto'g'ri HTML (validator xato beradi), lekin brauzer uni DOM'da shundayligicha qoldiradi. Shuning uchun "brauzer tuzatadi" degan gapga suyanmang — tuzatish qoidalari murakkab, natijasi esa siz kutgandek bo'lmasligi mumkin. To'g'ri HTML yozing.

7. DevTools'da DOM bilan ishlash

DevTools I darsida Elements panelida HTML'ni qo'lda tahrirlagansiz. Endi uni JavaScript bilan bog'laymiz. Kompyuterda, har qanday sahifada (masalan, o'z portfolio'ngizda) sinab ko'ring:

  1. Elements panelida biror elementni bosing. Uning yonida kulrang == $0 yozuvi paydo bo'ladi.
  2. Console'ga o'ting va yozing:
js
$0;                 // tanlangan element
$0.nodeName;        // masalan "H1"
$0.childNodes;      // uning bola tugunlari
$0.parentNode;      // otasi
console.dir($0);    // element obyektining barcha xususiyatlari

$0 — "Elements panelida hozir tanlangan element". U faqat DevTools konsolida ishlaydi, sizning kodingizda emas.

console.dir — console API darsida va'da qilingan foydasi shu: console.log($0) elementni HTML ko'rinishida chiqaradi, console.dir($0) esa uni obyekt sifatida ochadi — yuzlab xususiyatlar ro'yxati. Ro'yxat oxirida [[Prototype]] bandini bosib oching: HTMLHeadingElement → HTMLElement → Element → Node → EventTarget. Bu — «Tugun oilalari» bo'limidagi diagramma, brauzerning o'zida.

Jonli oynaning Konsol panelida ham farqni ko'rsa bo'ladi, lekin qisqa shaklda:

html
<h1 class="sarlavha">Menyu</h1>
<script>
  const sarlavha = document.querySelector("h1");
  console.log(sarlavha);
  console.dir(sarlavha);
</script>

Konsolda:

text
<h1 class="sarlavha">Menyu</h1>
h1.sarlavha

console.log — HTML ko'rinishi. console.dir — obyektning qisqa nomi: h1.sarlavha, ya'ni "sarlavha class'li h1 obyekti". Chrome konsoli ham uni xuddi shunday yozadi, faqat yonida uchburchak bo'ladi. Panelda uni ochib bo'lmaydi — obyektning ichini ko'rish DevTools'ning ishi.

Elements panelining yana uch foydali imkoniyati:

  • Selektor bilan qidirish. Elements panelida Ctrl+F bosing va CSS selektor yozing, masalan nav a. Panel mos elementlarni birma-bir ko'rsatadi va nechta topilganini yozadi. Keyingi darsdagi querySelectorAll ni kodga yozishdan oldin selektorni shu yerda sinash qulay.
  • Matn tugunlari ham ko'rinadi. Panel bo'sh joy tugunlarini yashiradi, lekin matnli tugunlar (masalan "Osh") element ichida alohida qator bo'lib turadi. Izohlar esa yashil rangda chiqadi.
  • Properties yorlig'i. O'ng tomondagi Styles yonida (ba'zan » belgisi ortida) Properties bor. U console.dir bilan bir xil ro'yxatni ko'rsatadi — tanlangan tugunning barcha xususiyatlari, oilalarga ajratilgan holda.

Maslahat: Elements panelida elementni o'ng tugma bilan bosib, Store as global variable ni tanlang. Console'da temp1 degan o'zgaruvchi paydo bo'ladi — u o'sha element. Bir nechta elementni saqlasangiz: temp2, temp3.

8. Ko'p uchraydigan xatolar

8.1 "Birinchi bola" — element emas

html
<ul id="menyu">
  <li>Osh</li>
  <li>Manti</li>
</ul>
<script>
  const menyu = document.querySelector("#menyu");
  console.log(menyu.firstChild.nodeName);
  console.log(menyu.firstChild.id);
</script>

Konsolda:

text
#text
undefined

Kutilgani — birinchi li. Haqiqatda — <ul> dan keyingi Enter va bo'sh joylar. Matn tugunida id yo'q, shuning uchun undefined. Xato chiqmaydi — shu sababli bu xato uzoq yashirinib yuradi. Tuzatish: element kerak bo'lsa — children[0] yoki firstElementChild (DOM bo'ylab harakatlanish).

8.2 nodeName ni kichik harf bilan solishtirish

js
if (tugun.nodeName === "li") {   // ❌ hech qachon true bo'lmaydi
  // ...
}
if (tugun.nodeName === "LI") {   // ✅
  // ...
}

HTML elementlarining nodeName i doim katta harfda. SVG elementlari esa yozilganidek qoladi (circle). Ishonchli yo'li — elementlarni CSS selektor bilan tekshirish, uni keyingi darsda matches bilan ko'ramiz.

8.3 JavaScript o'zgarishini Ctrl+U da qidirish

"Kodim ishlamayapti — sahifa manbasida yangi matn yo'q!" Manba hech qachon o'zgarmaydi. Elements panelini oching.

8.4 DevTools'dagi o'zgarishni saqlangan deb o'ylash

Elements panelida yoki Console'da DOM'ni o'zgartirsangiz, bu faqat shu tabda. F5 — hammasi qaytadi. Doimiy o'zgarish — faqat HTML yoki JS faylda.

9. Mashqlar

1-mashq (oson): Daraxtni chizing

Quyidagi HTML uchun daraxtni qog'ozda chizing. Bo'sh joylarni hisobga olmang (hammasi bitta qatorda yozilgan deb hisoblang). Nechta element va nechta matn tuguni bor?

html
<article><h2>Osh</h2><p>Narxi: <b>35 000</b> so'm</p></article>
Yechim
text
article
├── h2
│   └── "Osh"
└── p
    ├── "Narxi: "
    ├── b
    │   └── "35 000"
    └── " so'm"

Elementlar — 4 ta: article, h2, p, b. Matn tugunlari — 4 ta: "Osh", "Narxi: ", "35 000", " so'm". p ning uchta bolasi bor, children esa faqat bittasini (b) sanaydi.

2-mashq (o'rta): Element va matnni sanang

Quyidagi oynada karta ning bola tugunlarini aylanib chiqib, nechtasi element, nechtasi matn ekanini hisoblang. Natija: Element: 3, matn: 4.

Ishora: ikki hisoblagich let bilan, sikl ichida if va nodeType ni Node.ELEMENT_NODE yoki Node.TEXT_NODE bilan solishtirish.

html
<article id="karta">
  <h2>Manti</h2>
  <p>30 000 so'm</p>
  <p>Bug'da pishgan</p>
</article>
<script>
  const karta = document.querySelector("#karta");
  // shu yerga yozing
</script>
Yechim
html
<article id="karta">
  <h2>Manti</h2>
  <p>30 000 so'm</p>
  <p>Bug'da pishgan</p>
</article>
<script>
  const karta = document.querySelector("#karta");
  let elementlar = 0;
  let matnlar = 0;
  for (const tugun of karta.childNodes) {
    if (tugun.nodeType === Node.ELEMENT_NODE) {
      elementlar++;
    } else if (tugun.nodeType === Node.TEXT_NODE) {
      matnlar++;
    }
  }
  console.log(`Element: ${elementlar}, matn: ${matnlar}`);
</script>

Konsolda:

text
Element: 3, matn: 4

To'rtta matn tuguni — teglar orasidagi bo'sh joylar: <article> dan keyin, har </h2>, </p> dan keyin. Taqqoslash uchun: karta.children.length — 3.

3-mashq (qiyin): Oila zanjiri

<a> va <input> elementlari uchun: (1) constructor.name ni chiqaring; (2) har biri HTMLElement, Element, Node oilalariga tegishlimi — instanceof bilan tekshiring; (3) a.href va input.value ni chiqaring, keyin a.value ni ham. Nima uchun oxirgisi undefined?

Yechim
html
<a href="https://example.com/menyu">Menyu</a>
<input type="text" value="Ali" aria-label="Ism">
<script>
  const havola = document.querySelector("a");
  const maydon = document.querySelector("input");
  console.log(havola.constructor.name, maydon.constructor.name);
  console.log(havola instanceof HTMLElement);
  console.log(maydon instanceof Node);
  console.log(havola.href, maydon.value);
  console.log(havola.value);
</script>

Konsolda:

text
HTMLAnchorElement HTMLInputElement
true
true
https://example.com/menyu Ali
undefined

value — HTMLInputElement oilasining xususiyati. Havola bu oiladan emas, uning zanjiri HTMLAnchorElement → HTMLElement → Element → Node. Hech bir bo'g'inda value yo'q — shuning uchun undefined. Xuddi shunday, href ni input dan qidirish befoyda.

4-mashq: Portfolio qadami — sahifa tekshiruvchisi

O'tgan darsda portfolio'ga asosiy.js ni uladingiz. Endi unga kichik "nazoratchi" qo'shing: sahifa tuzilishida xato bo'lsa, konsolda sariq ogohlantirish chiqsin. Bu — dasturchilar uchun yordamchi, foydalanuvchi uni ko'rmaydi.

sahifaniTekshir funksiyasi uch narsani tekshirsin:

  1. document.doctype — null bo'lsa, DOCTYPE yo'q. Bunday sahifani brauzer eski "quirks" rejimida chizadi (Hujjat skeleti).
  2. document.documentElement.lang — <html> dagi lang atributining qiymati. Bo'sh satr bo'lsa, ekran o'quvchi sahifa tilini bilmaydi. (Atribut va xususiyat farqi — Atributlar, xususiyatlar va dataset darsida.)
  3. document.title — bo'sh yoki faqat probeldan iborat bo'lmasin (trim — Matnni tozalash).

Ogohlantirish uchun console.warn (console API). Funksiyani console.log qatoridan oldin chaqiring.

Yechim

sayt/assets/js/asosiy.js:

js
// asosiy.js — portfolio'ning umumiy skripti (09-qism)

function sahifaniTekshir() {
  if (document.doctype === null) {
    console.warn("DOCTYPE yo'q — sahifa quirks rejimida");
  }
  if (document.documentElement.lang === "") {
    console.warn("<html> da lang yo'q — til noma'lum");
  }
  if (document.title.trim() === "") {
    console.warn("<title> bo'sh — tabda nom ko'rinmaydi");
  }
}

sahifaniTekshir();
console.log(`asosiy.js ulandi: ${document.title}`);

Tekshiruvchi ishlashini "buzilgan" sahifada ko'ring — bu sahifada uchala xato bor:

html
<html>
<head>
  <title> </title>
</head>
<body>
  <p>Eski sahifa</p>
  <script>
    function sahifaniTekshir() {
      if (document.doctype === null) {
        console.warn("DOCTYPE yo'q — sahifa quirks rejimida");
      }
      if (document.documentElement.lang === "") {
        console.warn("<html> da lang yo'q — til noma'lum");
      }
      if (document.title.trim() === "") {
        console.warn("<title> bo'sh — tabda nom ko'rinmaydi");
      }
    }
    sahifaniTekshir();
  </script>
</body>
</html>

Konsolda:

text
DOCTYPE yo'q — sahifa quirks rejimida
<html> da lang yo'q — til noma'lum
<title> bo'sh — tabda nom ko'rinmaydi

Konsol panelida uchala qator sariq — console.warn shunday ko'rinadi. Portfolio'ngizda esa (04-qismdan beri hamma narsa joyida) ogohlantirish chiqmasligi kerak, faqat "asosiy.js ulandi". Bitta nozik joy: jonli oyna har doim standart rejimda chiziladi, shuning uchun quirks'ning o'zini bu yerda ko'ra olmaysiz — haqiqiy faylda DOCTYPE'ni o'chirsangiz, ko'rasiz.

Commit: JS: sahifa tuzilishi tekshiruvini qo'sh.

10. Real ishda

  • Har DOM xatosi daraxtdan boshlanadi. "Element topilmadi", "noto'g'ri element o'zgardi" — tajribali dasturchi avval Elements panelini ochib, DOM'ni ko'radi, keyin kodga qaraydi.
  • Freymvorklar (React, Vue — kursda alohida o'rganamiz) ham oxir-oqibat shu DOM tugunlarini yaratadi va o'zgartiradi. "Virtual DOM" degan atamani eshitsangiz — bu shu daraxtning JavaScript'dagi nusxasi.
  • Ekran o'quvchilar sahifani DOM'dan "o'qiydi". Malika NVDA bilan «Bahor» saytiga kirganda u eshitadigan narsa — DOM tuzilishi. To'g'ri daraxt — qulay sayt.
  • Avtomatik testlar ham DOM'ga qaraydi: test dasturi sahifani ochib, "tugma bosilgandan keyin ro'yxatda uchta element bormi?" deb tekshiradi. Testlarni kursda alohida qismda yozamiz — hozir bilish shart emas, lekin ular ham aynan shu daraxt bilan ishlashini biling.
  • Intervyuda: "DOM nima?", "childNodes va children farqi?", "Element va Node farqi?" — boshlang'ich darajadagi odatiy savollar.

Xulosa

  • DOM — HTML'dan qurilgan tugunlar daraxti; JavaScript faqat shu daraxt bilan ishlaydi.
  • Asosiy tugun turlari: element (1), matn (3), izoh (8), document (9), doctype (10).
  • Teglar orasidagi Enter va bo'sh joylar ham matn tuguni; childNodes ularni sanaydi, children — yo'q.
  • Ierarxiya: EventTarget → Node → Element → HTMLElement → HTMLLIElement; xususiyat qaysi darajada bo'lsa, o'shandan pastdagilarda bor.
  • DOM ≠ manba kodi: brauzer HTML'ni tuzatadi, JavaScript o'zgartiradi — Elements panelida jonli holat.

Keyingi dars: Elementlarni tanlash — daraxtdan kerakli elementni CSS selektor bilan topish: querySelector, closest, matches va ikki xil ro'yxat.

Manbalar

  • MDN: "Node", "Node: nodeType property", "Element", "HTMLElement" — developer.mozilla.org
  • MDN: "Whitespace in the DOM" — developer.mozilla.org
  • DOM Standard: "Nodes" — dom.spec.whatwg.org
  • Chrome DevTools: "Console Utilities API reference" ($0) — developer.chrome.com
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
DOM daraxti: tugun turlari va Node → Element → HTMLElement ierarxiyasi — IlmHamroh