Node xossalari: tur, teg va tarkib
Endi DOM tugunlarini chuqurroq o'rganamiz. Ular turli sinflarga tegishli bo'lib, har biri o'z xossalariga ega. Ushbu darsda tugunlarning turini, teg nomini va ichki tarkibini qanday o'qish va yozishni ko'rib chiqamiz โ bu DOM bilan har kunlik ishning asosi.
DOM tugun sinflari
Turli DOM tugunlari turli xossalarga ega bo'lishi mumkin. Masalan, <a> tegiga mos element tuguni havola bilan bog'liq xossalarga (href), <input> tuguni esa kiritish bilan bog'liq xossalarga (value) ega. Matn tugunlari esa element tugunlaridan farqli. Ammo ular orasida umumiy narsalar ham bor, chunki barcha DOM tugunlari bitta ierarxiyani tashkil etadi.
Har bir DOM tuguni tegishli sinfga tegishli. Ierarxiyaning ildizi โ EventTarget. Undan Node, undan esa boshqalari meros oladi:
- EventTarget โ abstrakt ildiz sinf. Bu sinf obyektlari hech qachon yaratilmaydi. U barcha tugunlar uchun asos bo'lib xizmat qiladi va hodisalarni (events) qo'llab-quvvatlash imkonini beradi;
- Node โ ham abstrakt sinf, barcha DOM tugunlari uchun asos. U asosiy daraxt funksionalligini beradi:
parentNode,nextSibling,childNodesva h.k. (ular getter'lar).Nodeobyektlari ham hech qachon to'g'ridan-to'g'ri yaratilmaydi. Undan aniq tugun sinflari meros oladi:Text,Element,Comment; - Element โ DOM elementlari uchun asosiy sinf. U element darajasidagi navigatsiyani (
nextElementSibling,children) va qidiruvni (getElementsByTagName,querySelector) beradi. Brauzerdagi elementlar faqat HTML uchun emas โ SVG uchun ham.HTMLElementsinfiElementdan meros oladi; - HTMLElement โ barcha HTML elementlar uchun asosiy sinf. Undan aniq HTML elementlar meros oladi:
HTMLInputElement(<input>uchun),HTMLBodyElement(<body>uchun),HTMLAnchorElement(<a>uchun) va h.k.
Ya'ni, biror aniq tugunning xossa va metodlari to'plami merosning natijasidir. Masalan, <input> uchun DOM obyekti quyidagilardan meros oladi (yuqoridan pastga): HTMLInputElement โ HTMLElement โ Element โ Node โ EventTarget โ Object.
// input elementining sinfini va merosini ko'ramiz
let input = document.body.querySelector('input');
alert(input.constructor.name); // HTMLInputElement
console.dir(elem) orqali ko'ring. Yoki spetsifikatsiyalarni o'qing: DOM (dom.spec.whatwg.org) va HTML (html.spec.whatwg.org). Ular murakkab, ammo to'liq.nodeType โ tugun turi
nodeType xossasi tugun turini bildiruvchi eski, ammo hali ishlatiladigan usul. U son qiymat qaytaradi:
elem.nodeType == 1โ element tugunlari uchun;elem.nodeType == 3โ matn tugunlari uchun;elem.nodeType == 9โdocumentobyekti uchun;- Boshqa qiymatlar ham bor (izohlar uchun 8 va h.k.), ammo bulari eng ko'p uchraydiganlari.
<body>
<script>
let elem = document.body;
// element tuguni ekanligini tekshiramiz
alert(elem.nodeType); // 1
// birinchi bolasi โ matn tuguni
alert(elem.firstChild.nodeType); // 3
// document obyekti uchun
alert(document.nodeType); // 9
</script>
</body>
instanceof yoki boshqa sinf-asosli tekshiruvlar orqali aniqlash mumkin. Ammo ba'zan nodeType eng sodda yo'l. Uni faqat o'qishimiz mumkin, o'zgartira olmaymiz.nodeName va tagName
Tugunning teg nomini nodeName yoki tagName orqali o'qishimiz mumkin:
alert( document.body.nodeName ); // BODY
alert( document.body.tagName ); // BODY
Ular orasida farq bormi? Bor, va u nozik:
tagNamexossasi FAQATElementtugunlarida mavjud;nodeNameesa har qandayNodeuchun aniqlanadi: elementlar uchun utagNamebilan bir xil, boshqa tugun turlari (matn, izoh) uchun esa tugun turini bildiruvchi maxsus satr qaytaradi.
<body>
<!-- izoh -->
<script>
// izoh uchun
alert( document.body.firstChild.nodeName ); // #comment
// document uchun
alert( document.nodeName ); // #document
</script>
</body>
Boshqacha aytganda, tagName faqat elementlarda ishlaydi (bu mantiqan to'g'ri โ faqat elementlarda teg bo'ladi), nodeName esa boshqa tugun turlari uchun ham biror-bir ma'lumot beradi.
tagName va nodeName teglarni BOSH harfda beradi: BODY, DIV, INPUT va h.k. (XML rejimida esa asl holicha saqlanadi, ammo bu kamdan-kam uchraydi).innerHTML โ tarkib
innerHTML xossasi elementning ichidagi HTML'ni satr sifatida olish yoki o'rnatish imkonini beradi. Bu eng ko'p ishlatiladigan xossalardan biri:
<body>
<p>Paragraf</p>
<div>DIV</div>
<script>
alert( document.body.innerHTML ); // joriy tarkibni o'qiydi
document.body.innerHTML = 'Yangi BODY!'; // to'liq almashtiradi
</script>
</body>
Biz ichiga noto'g'ri (buzuq) HTML kiritsak ham, brauzer uni o'qishda avtomatik tuzatadi:
document.body.innerHTML = '<b>test'; // yopilmagan teg
alert( document.body.innerHTML ); // <b>test</b> (avtomatik tuzatildi)
innerHTML += ... to'liq qayta yozadi! Bu jumla ichiga qo'shayotgandek ko'rinsa-da, aslida ikki qadamdan iborat: 1) eski tarkib o'chiriladi; 2) eski + yangi mazmun to'liq qayta yaratiladi. Bu esa muhim oqibatlarga ega: barcha rasmlar va boshqa resurslar qayta yuklanadi, oldingi tugunlarga bog'langan hodisa qayta ishlovchilari (event listeners) yo'qoladi, matn belgilangan (selection) bo'lsa โ u yo'qoladi.// masalan, bu barcha rasmlarni qayta yuklaydi (miltillash bo'lishi mumkin):
chatDiv.innerHTML += '<div>Salom<img src='smile.gif'/> !</div>';
chatDiv.innerHTML += 'Xayr <img src='goodbye.jpg'/> :)';
elem.insertAdjacentHTML yoki append/prepend metodlari. Ular mavjud tarkibni qayta yozmaydi. Bular bilan keyingi darslarda tanishamiz.outerHTML โ element bilan birga
outerHTML xossasi elementning to'liq HTML'ini โ elementning o'zini ham โ o'z ichiga oladi. Bu innerHTML ustiga element tegining o'zini qo'shgani bilan farq qiladi:
<div id="elem">Salom <b>Dunyo</b></div>
<script>
alert(elem.outerHTML); // <div id="elem">Salom <b>Dunyo</b></div>
</script>
outerHTMLga yozish elementni O'ZGARTIRMAYDI, balki uni ALMASHTIRADI! Ya'ni yangi HTML DOM'da eski elementning o'rniga qo'yiladi, ammo bizning eski elem o'zgaruvchisi hali ham eski (endi DOM'da bo'lmagan) elementga ishora qilib qoladi.<div>Salom, Dunyo!</div>
<script>
let div = document.querySelector('div');
// div.outerHTML'ni <p>...</p> bilan almashtiramiz
div.outerHTML = '<p>Yangi element!</p>';
// Diqqat! div hali ham eski qiymat!
alert(div.outerHTML); // <div>Salom, Dunyo!</div> (!)
// DOM'da esa endi <p> turibdi
</script>
Yuqoridagi kod ko'pchilikni chalkashtiradi. Sabab: div.outerHTML = ... divni DOM'dan olib tashladi va uning o'rniga yangi HTML qo'ydi. Ammo div o'zgaruvchisi hali ham eski elementga ishora qiladi. Yangi qo'shilgan tugunni olish uchun DOM'dan qayta topish kerak.
nodeValue va textContent
innerHTML faqat element tugunlarida ishlaydi. Boshqa tugun turlarida (matn, izoh) tarkibni o'qish uchun ularning "o'xshashlari" bor: nodeValue va data xossalari. Ular deyarli bir xil, amaliyotda kichik farqlari bilan:
<body>
Salom
<!-- Izoh -->
<script>
let text = document.body.firstChild;
alert(text.data); // Salom
let comment = text.nextSibling;
alert(comment.data); // Izoh
</script>
</body>
Matn tugunlari uchun ular ma'noli bo'ladi, izohlar uchun ham. Ammo element tugunlari uchun nega bizga ular kerak? Odatda kerak emas โ element uchun textContent foydaliroq.
textContent
textContent element ichidagi faqat matnni beradi โ barcha teglar tashlab yuboriladi, faqat matn qoladi:
<div id="news">
<h1>Sarlavha!</h1>
<p>Xabar matni.</p>
</div>
<script>
// Sarlavha! Xabar matni. (teglarsiz, faqat matn)
alert(news.textContent);
</script>
Amaliyotda uni o'qish kamdan-kam kerak, ammo yozish juda foydali. Chunki innerHTMLga matn yozsak, u HTML sifatida talqin qilinadi (teglar ishlaydi), textContentga yozsak esa matn AYNAN matn sifatida qo'yiladi โ barcha maxsus belgilar avtomatik xavfsiz "eskeyp" qilinadi:
<div id="elem1"></div>
<div id="elem2"></div>
<script>
let name = prompt('Ismingizni kiriting?', '<b>Salbarchi</b>');
// innerHTML: teg sifatida qo'yadi (xavfli!)
elem1.innerHTML = name; // <b>Salbarchi</b> โ qalin
// textContent: matn sifatida qo'yadi (xavfsiz)
elem2.textContent = name; // <b>Salbarchi</b> โ matn holicha ko'rinadi
</script>
textContent foydalanuvchi kiritgan matnni chiqarishda XAVFSIZLIK uchun juda muhim! Agar foydalanuvchi <script>...</script> yoki boshqa xavfli HTML kiritsa, innerHTML uni bajarishi mumkin (XSS hujumi). textContent esa uni oddiy matn deb qabul qiladi va hech qanday teg ishlamaydi.hidden xossasi
hidden atributi va DOM xossasi element ko'rinishmi yoki yashiringanmi ekanligini belgilaydi. Bu texnik jihatdan style="display:none" bilan bir xil ishlaydi, ammo yozishda qulayroq:
<div>Ikkalasi ham quyida yashiringan</div>
<div hidden>HTML atributi bilan</div>
<div id="elem">JavaScript xossasi bilan</div>
<script>
elem.hidden = true; // endi bu div ko'rinmaydi
</script>
hidden xossasi bilan biz elementni miltillatib (blinking) ko'rsatishimiz ham mumkin:
<div id="elem">Miltillovchi element</div>
<script>
setInterval(() => elem.hidden = !elem.hidden, 1000);
</script>
Boshqa xossalar
DOM elementlari yana ko'plab xossalarga ega. Xususan, aniq element sinfiga bog'liq bo'lganlari:
valueโ<input>,<select>,<textarea>uchun (HTMLInputElementva h.k.);hrefโ<a href="...">uchun (HTMLAnchorElement);idโ barcha elementlar uchunidatributining qiymati (HTMLElement).
<input type="text" id="elem" value="qiymat">
<script>
alert(elem.type); // text
alert(elem.id); // elem
alert(elem.value); // qiymat
</script>
Xulosa
- Har bir DOM tuguni tegishli sinfga ega. Sinflar ierarxiya tashkil qiladi:
EventTargetโNodeโElementโHTMLElementโ aniq element sinflari; nodeTypeโ tugun turini son bilan bildiradi (element=1, matn=3, document=9);tagName/nodeNameโ teg nomi (BOSH harfda);innerHTMLโ element ichidagi HTML (o'qish/yozish);outerHTMLโ element o'zi bilan birga HTML (yozish uni almashtiradi);nodeValue/dataโ matn va izoh tugunlari tarkibi;textContentโ faqat matn; foydalanuvchi kiritgan matnni xavfsiz chiqarishda muhim;hiddenโ elementni yashirish/ko'rsatish.