Hujjat (DOM)

Elementlarni qidirish: getElement*, querySelector*

DOM navigatsiyasi xossalari qo'shni tugunlar bir-biriga yaqin joylashganda juda qulay. Ammo elementlar bir-biridan uzoqda bo'lsa-chi? Sahifadagi istalgan elementni uning DOM'dagi o'rniga bog'liq bo'lmagan holda topish uchun maxsus qidiruv metodlari bor. Ushbu darsda ularni chuqur o'rganamiz.

document.getElementById yoki id

Agar elementning id atributi bo'lsa, uni document.getElementById(id) orqali topamiz, u qayerda bo'lishidan qat'i nazar:

<div id="elem">
  <div id="elem-content">Element</div>
</div>

<script>
  let elem = document.getElementById('elem');
  elem.style.background = 'red';
</script>

Bundan tashqari, idga ega global o'zgaruvchi avtomatik yaratiladi โ€” uning nomi id qiymatiga teng bo'ladi:

<div id="elem"></div>

<script>
  // elem โ€” id="elem" bo'lgan elementga havola
  alert(elem); // <div id="elem">

  // window.elem ham shu
  alert(window.elem === elem); // true
</script>
Bu "avtomatik global o'zgaruvchi" xususiyatiga TAYANMANG! U standartda tasvirlangan, ammo asosan orqaga moslik uchun saqlanadi. Brauzer bizning kodimizdagi o'zgaruvchi bilan idni chalkashtirib yuborishi mumkin. Agar kodda elem nomli o'zgaruvchi e'lon qilsak, u avtomatik global'ni bekor qiladi. Har doim document.getElementByIddan foydalanish yaxshi amaliyot.
Nomlar noyob (unique) bo'lishi kerak. Hujjatda faqat bitta element berilgan idga ega bo'lsin. Agar bir nechta element bir xil idga ega bo'lsa, qidiruv metodlarining xatti-harakati oldindan aytib bo'lmaydigan bo'ladi.
getElementById faqat document obyektida chaqiriladi, oddiy elementlarda emas: elem.getElementById(...) mavjud emas!

querySelectorAll

Eng ko'p qirrali metod โ€” elem.querySelectorAll(css). U berilgan CSS selektorga mos keluvchi barcha elementlarni qaytaradi.

<ul>
  <li>Bu</li>
  <li>test</li>
</ul>
<ul>
  <li>ancha</li>
  <li>uzun</li>
</ul>

<script>
  // har bir <ul>ning oxirgi <li>sini topamiz
  let elements = document.querySelectorAll('ul > li:last-child');

  for (let elem of elements) {
    alert(elem.innerHTML); // 'test', 'uzun'
  }
</script>

Bu metod juda kuchli, chunki har qanday CSS selektorni qo'llash mumkin. Hatto :hover va :active kabi psevdo-klasslar ham qo'llab-quvvatlanadi. Masalan, document.querySelectorAll(':hover') ustiga sichqoncha turgan elementlar to'plamini beradi.

querySelector

elem.querySelector(css) chaqiruvi berilgan CSS selektorga mos birinchi elementni qaytaradi.

Boshqacha aytganda, natija querySelectorAll(css)[0] bilan bir xil, ammo querySelectorAll barcha elementlarni topib to'plamdan birinchisini olsa, querySelector faqat birinchisini topadi. Shuning uchun u tezroq va yozishda ham qisqaroq:

let elem = document.querySelector('.my-class'); // birinchi mos element

matches

Oldingi metodlar DOM'da qidirar edi. elem.matches(css) esa hech narsa qidirmaydi. U faqat elem berilgan CSS selektorga mosligini tekshiradi va true yoki false qaytaradi.

Bu qandaydir to'plam (masalan, massiv) ustidan aylanib, kerakli elementlarni filtrlaganda foydali:

<a href="http://example.com/file.zip">...</a>
<a href="http://ya.ru">...</a>

<script>
  // faqat href oxiri zip bilan tugaydigan havolalar
  for (let elem of document.querySelectorAll('a')) {
    if (elem.matches('a[href$=".zip"]')) {
      alert('Arxivga havola: ' + elem.href);
    }
  }
</script>

closest

Elementning ajdodlari (ancestors) โ€” bu uning otasi, otasining otasi, uning otasi va hokazo. Ajdodlar birgalikda yuqoriga, ildizgacha bo'lgan zanjirni tashkil qiladi.

elem.closest(css) metodi berilgan CSS selektorga mos keluvchi eng yaqin ajdodni qidiradi. elemning o'zi ham qidiruvga kiritiladi.

Boshqacha aytganda, closest elementning o'zidan boshlab yuqoriga ko'tarilib boradi va har bir ajdodni selektorga tekshiradi. Mos kelgani topilsa, qidiruv to'xtaydi va shu ajdod qaytariladi:

<h1>Sarlavha</h1>
<div class="contents">
  <ul class="book">
    <li class="chapter">Bob 1</li>
    <li class="chapter">Bob 2</li>
  </ul>
</div>

<script>
  let chapter = document.querySelector('.chapter'); // LI

  alert(chapter.closest('.book')); // UL
  alert(chapter.closest('.contents')); // DIV

  alert(chapter.closest('h1')); // null (h1 ajdod emas)
</script>
closest hodisalarni qayta ishlashda (event delegation) juda ko'p ishlatiladi: bosilgan element atrofidagi kerakli "o'rovchi" (wrapper) elementni topish uchun ideal vosita.

getElementsBy* metodlari

Elementlarni teg, klass va boshqalar bo'yicha qidiruvchi eski metodlar ham bor. Bugun ular asosan querySelector foydasiga o'z ahamiyatini yo'qotmoqda, ammo eski kodlarda hali ko'p uchraydi:

// hujjatdagi barcha <div>lar
let divs = document.getElementsByTagName('div');

// jadvaldagi barcha input'larning qiymatini oling
let inputs = table.getElementsByTagName('input');
for (let input of inputs) {
  alert( input.value );
}
Metod nomida "s" harfiga e'tibor bering! Yangi boshlovchilar ba'zan xato qiladi: getElementByTagName (bittalik) โ€” mavjud emas! To'g'ri nomi getElementsByTagName (ko'plik, chunki bir nechta element qaytaradi). Aksincha, getElementById bitta element qaytargani uchun "s"siz yoziladi.
Ba'zilar getElementsByTagName to'plam qaytarishini unutib, uni to'g'ridan-to'g'ri element deb ishlatadi: document.getElementsByTagName('input').value ishlamaydi! To'g'risi โ€” element indeksini olish: document.getElementsByTagName('input')[0].value.

Jonli (live) va statik to'plamlar

Bu yerda muhim farq bor:

// jonli to'plam
let divs = document.getElementsByTagName('div');
alert(divs.length); // masalan, 1

// hujjatga yangi <div> qo'shsak...
document.body.append(document.createElement('div'));

alert(divs.length); // 2 (avtomatik yangilandi!)
// statik to'plam
let divs = document.querySelectorAll('div');
alert(divs.length); // masalan, 1

document.body.append(document.createElement('div'));

alert(divs.length); // hali ham 1 (o'zgarmaydi)
Bu farqni bilish muhim: agar to'plamni saqlab, keyin DOM'ni o'zgartirsangiz, jonli to'plamda yangi elementlar paydo bo'ladi, statik to'plamda esa yo'q. Ko'p hollarda statik (querySelectorAll) xatti-harakat oldindan aytiluvchan bo'lgani uchun qulayroq.

elemA.contains(elemB)

Yana bir foydali metod โ€” elemA.contains(elemB). U elemB elemA ichida (uning avlodi) yoki elemA === elemB bo'lsa, true qaytaradi:

// tekshirish: parent element child'ni o'z ichiga oladimi?
if (parentElem.contains(childElem)) {
  alert('child parent ichida');
}

Barcha 6 metod umumiy jadval

Qidiruv metodlarini eslab qolish uchun umumiy ko'rinish:

Amaliyotda 99% hollarda querySelector va querySelectorAll yetarli. Ular eng moslashuvchan va yodda tutish oson. getElementById esa juda tez bo'lgani va oddiyligi tufayli id bo'yicha qidirishda hali ham ommabop.

Xulosa