Pohon DOM

document.querySelector dan penelusuran node pada pohon DOM.

Daftar isi

Setiap halaman yang ditampilkan browser dapat diakses oleh JavaScript melalui DOM (Document Object Model), yaitu representasi pohon yang dibangun browser dari dokumen HTML. Topik ini menelusuri pohon itu mulai dari titik masuknya, memilih elemen tertentu dengan querySelector dan querySelectorAll, lalu menjelajahi hubungan antarelemen lewat parentElement, children, dan nextElementSibling. Seluruh contoh berjalan di browser, dan demo di bagian akhir dapat dicoba langsung untuk melihat hasil seleksinya.

Browser membangun pohon dari HTML#

Saat sebuah halaman dimuat, browser membaca HTML dari atas ke bawah dan menyusunnya menjadi pohon node, yakni titik-titik yang mewakili bagian dokumen, mulai dari elemen, teks, sampai komentar. Pasangan tag pembuka dan penutup menentukan hubungan antarelemen, sehingga elemen <ul> yang menampung beberapa <li> menjadi induk dengan anak-anak di bawahnya. Puncak aksesnya adalah object document, yang mewakili seluruh dokumen dan menjadi titik awal hampir semua pencarian elemen. document sendiri merupakan node pula, dan posisinya di puncak menjadikannya pembungkus dari seluruh elemen halaman. JavaScript tidak pernah membaca berkas HTML secara langsung, karena semua yang dilihatnya adalah pohon yang dibangun browser tersebut.

Diagram berikut memperlihatkan potongan pohon untuk satu halaman kecil yang berisi judul dan daftar. Rantai document sampai ul itulah yang dilalui setiap pencarian elemen.

documenthtmlheadbodytitleh1ullilililipohon dibangunsaat halamandimuattitik akses:document
Potongan pohon DOM untuk halaman dengan satu judul dan daftar empat item, dari document sampai node li

Urutan susunannya sejajar dengan kedalaman tag. Elemen paling luar berada paling dekat dengan document, sedangkan elemen yang bersarang makin dalam menempati posisi makin jauh pada pohon. Pohon ini hidup di memori dan dapat diubah setiap saat, misalnya menambah anak baru pada ul tanpa menyentuh berkas HTML aslinya. Perubahan apa pun langsung tercermin di layar karena browser menggambar tampilan dari pohon yang sama.

Memilih elemen dengan querySelector dan querySelectorAll#

Metode document.querySelector() menerima satu selektor CSS dan mengembalikan elemen pertama yang cocok, sedangkan document.querySelectorAll() mengembalikan semua kecocokan sekaligus. Selektornya sama dengan yang dipakai di berkas CSS, sehingga #daftar menunjuk elemen dengan id daftar, .aktif menunjuk elemen dengan atribut class aktif, dan #daftar li menunjuk semua li di dalam daftar itu. Bila tidak ada yang cocok, querySelector mengembalikan null dan querySelectorAll mengembalikan koleksi kosong, bukan error.

js Contoh: memilih elemen pertama yang cocok
// tidak-dijalankan
const judul = document.querySelector("h1");
const daftar = document.querySelector("#daftar");
const itemPertama = document.querySelector("#daftar li");

console.log(judul.textContent);      // teks di dalam h1
console.log(itemPertama.textContent); // item li pertama pada daftar

Hasil querySelectorAll berupa NodeList, yaitu koleksi berisi semua node yang cocok berurutan sesuai posisinya di dokumen. Koleksi ini dapat ditelusuri dengan for...of, dan metode forEach juga tersedia di dalamnya.

js Contoh: menelusuri semua kecocokan dengan for...of
// tidak-dijalankan
const semuaItem = document.querySelectorAll("#daftar li");

for (const item of semuaItem) {
  console.log(item.textContent);
}

Menelusuri pohon lewat induk dan tetangga#

Setelah satu elemen terpilih, hubungannya dengan elemen lain dapat diikuti lewat beberapa properti. Properti parentElement menunjuk induk langsungnya, children mengumpulkan semua elemen anak berurutan, dan nextElementSibling beserta previousElementSibling menunjuk elemen tetangga pada tingkat yang sama. Properti-properti ini membuat perpindahan antarelemen tidak memerlukan pencarian baru dari document.

js Contoh: menelusuri dari satu item ke induk dan tetangganya
// tidak-dijalankan
const item = document.querySelector("#daftar li");

console.log(item.parentElement.id);           // daftar
console.log(item.children.length);            // 0, li ini tidak punya anak
console.log(item.nextElementSibling.textContent); // teks item kedua

Perpaduan selektor dan penelusuran inilah keterampilan dasar bekerja dengan DOM. Cari satu titik awal dengan querySelector, lalu bergerak ke sekitarnya dengan properti keluarganya. Demo berikut memperagakan keduanya pada satu daftar kecil. Klik tombol Hitung item untuk melihat children.length dari daftar, tombol Tandai item kedua untuk memberi class pada children[1], dan tombol Periksa tetangga untuk membaca induk beserta tetangga item kedua.

Kode sumber demo
<!DOCTYPE html>
<html lang="id">
<head>
  <meta charset="UTF-8">
  <title>Demo seleksi dan penelusuran pohon DOM</title>
  <style>
    body { font-family: "Segoe UI", Arial, sans-serif; margin: 14px; font-size: 14px; color: #1f2937; }
    button { padding: 6px 12px; margin-right: 8px; margin-bottom: 10px; cursor: pointer; }
    #daftar { background: #f1f5f9; border: 1px solid #94a3b8; border-radius: 8px; padding: 10px 10px 10px 34px; max-width: 320px; }
    #daftar li { padding: 2px 6px; }
    #daftar li.terpilih { background: #fde68a; font-weight: 700; }
    #info { margin-top: 12px; padding: 10px; background: #eef2ff; border: 1px solid #4338ca; border-radius: 8px; min-height: 20px; max-width: 380px; }
  </style>
</head>
<body>
  <p>Daftar alat tulis di meja kerja:</p>
  <ul id="daftar">
    <li>Pensil</li>
    <li>Buku catatan</li>
    <li>Penghapus</li>
    <li>Penggaris</li>
  </ul>
  <button id="tombol-hitung" type="button">Hitung item</button>
  <button id="tombol-tandai" type="button">Tandai item kedua</button>
  <button id="tombol-tetangga" type="button">Periksa tetangga</button>
  <div id="info">Hasil seleksi akan tampil di sini.</div>
  <script src="index.js"></script>

<script>
// Demo pohon DOM: memilih elemen lalu menelusuri induk, anak, dan tetangganya.

const daftar = document.querySelector("#daftar");
const info = document.querySelector("#info");
const itemKedua = daftar.children[1];

document.querySelector("#tombol-hitung").addEventListener("click", () => {
  info.textContent = "children.length dari ul adalah " + daftar.children.length + ".";
});

document.querySelector("#tombol-tandai").addEventListener("click", () => {
  itemKedua.classList.add("terpilih");
  info.textContent = "children[1] yaitu \"" + itemKedua.textContent + "\" diberi class terpilih.";
});

document.querySelector("#tombol-tetangga").addEventListener("click", () => {
  const induk = itemKedua.parentElement.tagName;
  const sebelum = itemKedua.previousElementSibling.textContent;
  const sesudah = itemKedua.nextElementSibling.textContent;
  info.textContent = "Induknya " + induk + ", sebelumnya \"" + sebelum + "\", sesudahnya \"" + sesudah + "\".";
});

</script>
<script>
// Demo pohon DOM: memilih elemen lalu menelusuri induk, anak, dan tetangganya.

const daftar = document.querySelector("#daftar");
const info = document.querySelector("#info");
const itemKedua = daftar.children[1];

document.querySelector("#tombol-hitung").addEventListener("click", () => {
  info.textContent = "children.length dari ul adalah " + daftar.children.length + ".";
});

document.querySelector("#tombol-tandai").addEventListener("click", () => {
  itemKedua.classList.add("terpilih");
  info.textContent = "children[1] yaitu \"" + itemKedua.textContent + "\" diberi class terpilih.";
});

document.querySelector("#tombol-tetangga").addEventListener("click", () => {
  const induk = itemKedua.parentElement.tagName;
  const sebelum = itemKedua.previousElementSibling.textContent;
  const sesudah = itemKedua.nextElementSibling.textContent;
  info.textContent = "Induknya " + induk + ", sebelumnya \"" + sebelum + "\", sesudahnya \"" + sesudah + "\".";
});

</script></body>
</html>

Kesalahan umum#

  1. Mencari elemen sebelum HTML-nya tersedia. Script yang dijalankan di <head> menemukan body yang masih kosong, sehingga querySelector mengembalikan null dan baris berikutnya melempar error. Letakkan tag <script> di akhir body, atau tunda pencarian sampai event DOMContentLoaded dipancarkan.
  2. Menulis selektor pada properti penelusuran. Properti keluarga seperti parentElement dan children tidak menerima selektor. querySelector yang dipanggil pada satu elemen juga hanya mencari di dalam turunannya, bukan ke arah atas. Tentukan arah pergerakan lebih dahulu, yaitu ke bawah dengan selektor dan ke samping atau ke atas dengan properti keluarga.
  3. Mengira hasil querySelectorAll berupa array. Hasilnya adalah NodeList yang cukup untuk for...of dan forEach, tetapi tidak memiliki metode array seperti map dan filter. Konversi dengan Array.from() bila metode array tersebut dibutuhkan.

Ringkasan#

  • Browser menyusun HTML menjadi pohon node yang dapat diakses dari object document, dan setiap perubahan pada pohon langsung terlihat di halaman.
  • querySelector mengembalikan kecocokan pertama atau null, sedangkan querySelectorAll mengembalikan NodeList berisi semua kecocokan yang siap ditelusuri.
  • Hubungan antarelemen ditelusuri lewat parentElement, children, previousElementSibling, dan nextElementSibling, yang semuanya bekerja pada elemen saja.
  • Pencarian dan penelusuran saling melengkapi, satu titik awal dicari dengan selektor, sisanya dijelajahi lewat properti keluarga.

Referensi#