DOM nedir ve neden “seçme + güncelleme” iki temel adımdır?
Web sayfasındaki görünen (ve görünmeyen) tüm yapı taşları, tarayıcı içinde DOM (Document Object Model) denen ağaç yapısıyla temsil edilir. JavaScript ile arayüzü değiştirmek genellikle iki adımda ilerler:
- Element seçme: Hangi düğüm(ler) üzerinde çalışacağını belirlemek.
- Güncelleme: Metin, sınıf (class), öznitelik (attribute) veya çocuk düğümleri değiştirmek.
Bu yazı, “günlük iş” ihtiyaçlarını hedefler: doğru seçiciyi yazmak, null kontrolü yapmak, metni güvenli biçimde güncellemek ve class yönetimini temiz tutmak.
1) Element seçme: querySelector ve querySelectorAll
document.querySelector(): ilk eşleşeni seçer (yoksa null)
document.querySelector(selectors), verdiğiniz CSS seçiciyle eşleşen ilk elementi döndürür; eşleşme yoksa null döner. Bu davranış hem pratik kaynaklarda hem de DOM Standard tanımında yer alır.
Kaynaklar: MDN querySelector(), WHATWG DOM Standard.
Örnek: tek bir elementi güvenli şekilde seçip güncellemek
const titleEl = document.querySelector('h1');
if (titleEl) {
titleEl.textContent = 'Merhaba DOM!';
}
Neden null kontrolü? Çünkü seçici sayfada yoksa, dönen değer null olur ve doğrudan özellik çağırmak hata üretir. Giriş seviyesinde en sık atlanan adımlardan biri budur.
querySelectorAll(): birden çok eşleşme ve statik NodeList
element.querySelectorAll(selectors) (ve document üzerinde kullanımı), eşleşen tüm elementleri bir NodeList olarak döndürür. Bu listenin statik olduğu (DOM sonradan değişse bile listenin kendiliğinden güncellenmeyebileceği) DOM Standard’da tanımlanır.
Kaynak: WHATWG DOM Standard.
Örnek: çoklu elementi döngüyle güncellemek
document.querySelectorAll('.tag').forEach((el) => {
el.textContent = '#javascript';
});
İpucu: NodeList çoğu modern tarayıcıda forEach destekler; ancak daha geniş uyumluluk gerekiyorsa Array.from(...) ile diziye çevirmek iyi bir alışkanlık olabilir.
Seçimi daraltın: element.querySelector ile “scope” kullanımı
Büyük sayfalarda, tüm document üzerinde aramak yerine önce bir kapsayıcı seçip onun içinde aramak hem okunabilirliği artırır hem de yanlış eşleşme riskini azaltır.
const card = document.querySelector('.product-card');
if (card) {
const price = card.querySelector('.price');
if (price) price.textContent = '$19.99';
}
2) Metin güncelleme: textContent, innerText ve innerHTML farkı
textContent: ham metin okur/yazar
textContent, bir düğümün metin içeriğini (alt düğümler dahil) “ham metin” olarak okur ve yazar. Arayüzde görünen metni güncellemenin en güvenli ve basit yollarından biridir.
Kaynak: MDN: Node.textContent.
Örnek: kullanıcıya durum mesajı göstermek
const statusEl = document.querySelector('#status');
if (statusEl) {
statusEl.textContent = 'Yükleme tamamlandı.';
}
innerText: görünür metne odaklanır, stil/yerleşim etkileri olabilir
innerText çoğunlukla “görünen metin” ile ilgilidir ve bazı durumlarda stil/ görünürlük hesaplamalarından etkilenebilir. MDN, innerText’in okuma sırasında yerleşim hesaplamalarını (reflow) tetikleyebileceğine dair notlar paylaşır. Bu nedenle, yalnızca gerçekten “görünen metni” hedeflediğiniz durumlarda kullanmak daha temkinli bir yaklaşımdır.
Kaynak: MDN: Node.textContent (innerText karşılaştırmaları).
innerHTML: HTML ayrıştırır; dış veride dikkat gerektirir
innerHTML, verdiğiniz string’i HTML olarak ayrıştırıp DOM’a yazar. Bu pratik görünebilir; ancak içerik kullanıcıdan veya harici bir kaynaktan geliyorsa, uygun şekilde temizlenmeden (sanitize edilmeden) kullanmak ciddi güvenlik riskleri doğurabilir. Metin basmak istiyorsanız genellikle textContent tercih edilir.
Kaynak: MDN: Node.textContent.
Pratik kural: Hangi durumda hangisi?
- Sadece yazı güncelle: textContent
- “Görünür metin” davranışı önemli: innerText (gerektiğinde)
- Kontrollü, sabit HTML şablonu: Dikkatle innerHTML (dış veride sanitize düşün)
3) class yönetimi: classList ile durum (state) yönetimi
CSS sınıflarını string birleştirerek yönetmek yerine classList ile yönetmek daha okunabilir ve daha az sürprizli bir yaklaşımdır. add/remove/toggle/contains gibi metotlar sunar.
Kaynak: MDN: Element.classList.
Örnek: aktif/pasif görünümü toggle etmek
const panel = document.querySelector('.panel');
if (panel) {
panel.classList.toggle('is-open');
}
Örnek: bir sınıf var mı kontrol etmek
const btn = document.querySelector('.cta');
if (btn && !btn.classList.contains('disabled')) {
btn.classList.add('highlight');
}
Not: classList kullanımı, sınıf adlarının “boşlukla ayrılan liste” mantığıyla düzgün yönetilmesini kolaylaştırır.
4) Sık güncellenen diğer şeyler: attribute vs property
DOM’da bazı değerler hem “attribute” hem de “property” olarak karşınıza çıkar. Pratikte şu yaklaşım iş görür:
- Girdi değerleri (ör. input.value gibi) çoğunlukla property üzerinden yönetilir.
- Standart HTML öznitelikleri (ör. href, aria-*, data-*) için setAttribute/getAttribute kullanılabilir.
Örnek: data attribute ile durum tutmak
const item = document.querySelector('.item');
if (item) {
item.setAttribute('data-state', 'ready');
const state = item.getAttribute('data-state');
console.log(state);
}
5) DOM güncelleme örnekleri: küçük görevlerle pratik
Örnek A: Liste elemanlarını toplu güncelleme
Diyelim ki bir ürün listesinde tüm fiyat etiketlerini güncellemek istiyorsunuz. İlk olarak hepsini seçin, sonra tek bir döngüyle metni değiştirin:
document.querySelectorAll('.price').forEach((el) => {
el.textContent = '$0.00';
});
Örnek B: Bir kart içindeki alanları hedefleyerek güncelleme
Kart bazlı UI’larda, aynı sınıf isimleri birden çok yerde tekrar eder. Bu durumda “önce kartı seç, sonra içeride ara” yaklaşımı düzen sağlar:
const cards = document.querySelectorAll('.product-card');
cards.forEach((card) => {
const nameEl = card.querySelector('.name');
const badgeEl = card.querySelector('.badge');
if (nameEl) nameEl.textContent = 'Yeni Ürün';
if (badgeEl) badgeEl.classList.add('is-new');
});
6) Performans notu: çok sayıda değişikliği “toplu” uygulamayı düşünün
Birkaç element güncellemesinde genellikle sorun yaşamazsınız. Ancak çok sayıda düğüm ekleyip çıkarıyorsanız, her küçük değişikliği tek tek yapmak tarayıcı tarafında ek maliyetler doğurabilir. Bu gibi senaryolarda DocumentFragment veya replaceChildren gibi yaklaşımlar “toplu güncelleme” için düşünülebilir.
DOM Standard, düğüm ekleme/çıkarma ve replaceChildren gibi işlemlerin nasıl çalıştığını tanımlar. Kaynak: WHATWG DOM Standard.
Örnek: replaceChildren ile listeyi tek seferde yenilemek
Aşağıdaki örnekte, yeni liste elemanlarını önce fragment’e kurup ardından tek hamlede değiştirirsiniz. Bu, kodu daha “toplu” hale getirir:
const list = document.querySelector('#results');
if (list) {
const frag = document.createDocumentFragment();
['A', 'B', 'C'].forEach((label) => {
const li = document.createElement('li');
li.textContent = label;
frag.append(li);
});
list.replaceChildren(frag);
}
Sınır: Bu yazı benchmark (ölçüm) verisi sunmaz. Gerçek performans; DOM boyutu, cihaz ve tarayıcıya göre değişir. Büyük ölçekli güncellemelerde ölçüm yaparak ilerlemek daha sağlıklıdır.
7) Mini kontrol listesi: DOM ile çalışırken daha az sürpriz için
- Seçici sonrası null kontrolü yapın (özellikle querySelector ile).
- Metin basmak için önce textContent düşünün.
- Dış kaynaktan gelen HTML string’ini innerHTML’e doğrudan basmamaya çalışın; gerekiyorsa temizleme yaklaşımını planlayın.
- Class yönetiminde string birleştirmek yerine classList kullanın.
- Çok sayıda güncellemede fragment/replaceChildren gibi toplu yaklaşımları değerlendirin.
Kaynaklar ve notlar
Bu rehber, temel davranışlar için WHATWG DOM Standard ve MDN dokümantasyonuna dayanır. Tarayıcılar arası davranış farklılıkları ve ileri seviye güvenlik (sanitize stratejileri, politika tabanlı korumalar) gibi konular için ek araştırma gerekebilir.