Element Seçme ve Değiştirme
Giriş — DOM'a El Uzatmak
Bir önceki derste DOM'un ne olduğunu öğrendik — tarayıcının HTML belgesini hafızasında canlı bir ağaç olarak tuttuğunu, JavaScript'in bu ağaç üzerinden sayfayla etkileşime geçtiğini gördük. Ama DOM ağacını sadece seyretmenin bir anlamı yok; asıl güç, ağacın dallarına uzanıp onları değiştirmekte.
Kullanıcı bir butona tıkladığında başlığın rengini değiştirmek, bir formun hata mesajını göstermek, sepetteki ürün sayısını güncellemek — bunların hepsi aynı iki adımlık süreçle yapılır:
Seç — Değiştirmek istediğin elementi bul
Değiştir — İçeriğini, stilini, sınıfını, attribute'larını güncelle
Analoji: Bir kütüphanede kitap aramak gibi düşünün. Önce kitabı bulmanız gerekir — raf numarasıyla, yazar adıyla veya konuyla arayabilirsiniz. Sonra kitabı elinize aldığınızda, sayfasını açar, ayraç koyar, üzerine not düşersiniz. DOM manipülasyonu da aynıdır: önce element seçilir, sonra üzerinde işlem yapılır.
Element Seçme Yöntemleri
querySelector — Modern ve Güçlü
querySelector, CSS selector sözdizimini kullanarak ilk eşleşen elementi döndürür. Günümüzde en çok kullanılan seçim yöntemidir.
// ID ile seçim (#)
const baslik = document.querySelector("#ana-baslik");
// Class ile seçim (.)
const ilkKart = document.querySelector(".kart");
// Etiket ile seçim
const ilkParagraf = document.querySelector("p");
// Attribute ile seçim
const emailInput = document.querySelector('input[type="email"]');
// Hiyerarşik seçim
const navLink = document.querySelector("nav > ul > li:first-child > a");
// Pseudo-class ile seçim
const sonListeOgesi = document.querySelector("li:last-child");
const ucuncuKart = document.querySelector(".kart:nth-child(3)");
// Birden fazla selector (ilk eşleşen)
const baslikVeyaParagraf = document.querySelector("h1, h2, h3");
// Bulunamazsa null döner
const yok = document.querySelector("#olmayan-element");
console.log(yok); // nullquerySelectorAll — Tüm Eşleşenler
querySelectorAll, CSS selector'ına uyan tüm elementleri statik bir NodeList olarak döndürür.
// Tüm paragrafları seç
const paragraflar = document.querySelectorAll("p");
console.log(paragraflar.length); // Sayfadaki paragraf sayısı
// Tüm .kart elementlerini seç
const kartlar = document.querySelectorAll(".kart");
// NodeList üzerinde döngü
kartlar.forEach((kart, index) => {
console.log(`Kart ${index + 1}:`, kart.textContent);
});
// for...of ile döngü
for (const kart of kartlar) {
kart.classList.add("aktif");
}
// NodeList → Array dönüşümü (Array metotlarını kullanmak için)
const kartDizisi = Array.from(kartlar);
// veya
const kartDizisi2 = [...kartlar];
// Array metotları artık kullanılabilir
const aktifKartlar = kartDizisi.filter(k => k.classList.contains("aktif"));
const kartMetinleri = kartDizisi.map(k => k.textContent);⚠️ Dikkat: querySelectorAll statik bir NodeList döndürür — DOM değişikliklerinden etkilenmez. getElementsByClassName ve getElementsByTagName ise canlı (live) bir HTMLCollection döndürür — DOM değişince otomatik güncellenir. Bu fark, döngüde element silerken kritiktir.
Eski Yöntemler (getElementById, getElementsBy*)
Bu yöntemler hâlâ çalışır ve bazı durumlarda kullanılır, ama querySelector çoğu senaryoda yeterlidir:
// getElementById — ID ile seçim (en hızlı DOM sorgusu)
const element = document.getElementById("ana-baslik");
// Not: # işareti KULLANILMAZ — sadece ID string'i
// getElementsByClassName — LIVE HTMLCollection döndürür
const kartlar = document.getElementsByClassName("kart");
// Dikkat: forEach yok! for döngüsü veya Array.from gerekir
// getElementsByTagName — LIVE HTMLCollection
const paragraflar = document.getElementsByTagName("p");
// getElementsByName — name attribute ile seçim
const cinsiyet = document.getElementsByName("cinsiyet");Ne Zaman Hangisi?
| Yöntem | Döndürdüğü | Live/Static | Ne Zaman Kullan | |
|---|---|---|---|---|
querySelector | Element \ | null | — | Tek element seçmek (en çok kullanılan) |
querySelectorAll | NodeList | Static | Birden fazla element (en çok kullanılan) | |
getElementById | Element \ | null | — | Performans kritik, çok sık sorgu yapılıyorsa |
getElementsByClassName | HTMLCollection | Live | DOM değişikliklerini otomatik takip etmek gerekiyorsa | |
getElementsByTagName | HTMLCollection | Live | Nadir kullanılır |
💡 İpucu: Başlangıç olarak sadece querySelector ve querySelectorAll öğrenmeniz yeterli. Bu iki metot CSS selector gücünü kullanır ve neredeyse her senaryoyu karşılar. getElementById sadece performans kritik durumlarda küçük bir avantaj sağlar.
Element Üzerinden Arama (Scoped Query)
querySelector ve querySelectorAll sadece document üzerinde değil, herhangi bir element üzerinde de çalışır:
// Tüm sayfada arama
const ilkKart = document.querySelector(".kart");
// Sadece belirli bir container içinde arama
const sidebar = document.querySelector("#sidebar");
const sidebarLinki = sidebar.querySelector("a"); // Sadece sidebar içinde arar
const sidebarKartlar = sidebar.querySelectorAll(".kart"); // Sadece sidebar'daki kartlar
// Pratik örnek: Form içindeki input'ları bulma
const form = document.querySelector("#kayitFormu");
const emailInput = form.querySelector('input[name="email"]');
const sifreInput = form.querySelector('input[name="sifre"]');İçerik Değiştirme
Element seçildikten sonra, içeriğini değiştirmek en temel DOM operasyonudur. Üç ana yöntem vardır ve aralarındaki farkları bilmek güvenlik ve performans açısından kritiktir.
textContent — Güvenli Metin
textContent, bir elementin metin içeriğini okur veya değiştirir. HTML etiketlerini işlemez — her şey düz metin olarak ele alınır.
const baslik = document.querySelector("#baslik");
// Okuma
console.log(baslik.textContent); // "Merhaba Dünya"
// Yazma — mevcut içeriğin tamamı değişir
baslik.textContent = "Yeni Başlık";
// HTML etiketleri metin olarak görünür (güvenli!)
baslik.textContent = "<em>Kalın</em> metin";
// Ekranda görünen: <em>Kalın</em> metin (HTML olarak işlenmez!)
// Tüm alt elementlerin metnini birleştirir
// <div id="box"><span>Ali</span> <em>Veli</em></div>
const box = document.querySelector("#box");
console.log(box.textContent); // "Ali Veli"innerText — Görünür Metin
innerText, textContent'e benzer ama önemli farkları vardır:
// HTML:
// <p id="mesaj">
// Görünür metin
// <span style="display: none">Gizli metin</span>
// <br>
// İkinci satır
// </p>
const mesaj = document.querySelector("#mesaj");
// textContent — TÜM metni döndürür (gizli dahil)
console.log(mesaj.textContent);
// "Görünür metin Gizli metin İkinci satır"
// innerText — GÖRÜNÜR metni döndürür (CSS'i hesaba katar)
console.log(mesaj.innerText);
// "Görünür metin\nİkinci satır"| Özellik | textContent | innerText |
|---|---|---|
| Gizli elementler | Dahil eder | Hariç tutar |
| CSS etkisi | Yok | display: none görmez |
<br> etiketleri | Yok sayar | \n olarak yansıtır |
| Performans | Hızlı | Yavaş (reflow tetikler!) |
| Kullanım | Genel metin işleme | Kullanıcıya görüneni almak |
💡 İpucu: Çoğu durumda textContent kullanın — daha hızlıdır ve tahmin edilebilir davranır. innerText sadece CSS tarafından gizlenen metinleri hariç tutmanız gerektiğinde tercih edin.
innerHTML — HTML İçerik
innerHTML, bir elementin HTML içeriğini okur veya değiştirir. HTML etiketleri parse edilir ve DOM'a eklenir.
const container = document.querySelector("#container");
// Okuma — HTML string'i döndürür
console.log(container.innerHTML);
// "<h1>Başlık</h1><p>Paragraf</p>"
// Yazma — HTML parse edilir ve DOM'a eklenir
container.innerHTML = "<h2>Yeni Başlık</h2><p>Yeni paragraf</p>";
// Mevcut içeriğe ekleme
container.innerHTML += "<p>Eklenen paragraf</p>";
// ⚠️ Dikkat: Bu tüm içeriği yeniden parse eder!
// Mevcut event listener'lar kaybolur!
// Liste oluşturma
const urunler = ["Laptop", "Telefon", "Tablet"];
const liste = document.querySelector("#urunListesi");
liste.innerHTML = urunler
.map(urun => `<li class="urun-item">${urun}</li>`)
.join("");⚠️ GÜVENLİK UYARISI — XSS (Cross-Site Scripting):
// ❌ Kullanıcı girdisini innerHTML ile DOM'a ekleme — TEHLİKELİ!
const kullaniciYorumu = '<img src=x onerror="alert(document.cookie)">';
container.innerHTML = kullaniciYorumu; // 🔴 Script çalışır! XSS açığı!
// ❌ Başka bir XSS örneği
const kötüGirdi = '<a href="javascript:alert(1)">Tıkla</a>';
container.innerHTML = kötüGirdi; // 🔴 Tıklanınca script çalışır!
// ✅ Kullanıcı girdisi için textContent kullanın — güvenli!
container.textContent = kullaniciYorumu;
// Ekranda düz metin olarak görünür, script çalışmaz
// ✅ Veya sanitize edin
function sanitize(str) {
const div = document.createElement("div");
div.textContent = str;
return div.innerHTML; // HTML entities'e çevrilmiş string
}
container.innerHTML = sanitize(kullaniciYorumu); // GüvenliTemel kural: Kullanıcıdan gelen veriyi asla doğrudan innerHTML'e yazmayın. textContent kullanın veya öncesinde sanitize edin.
outerHTML — Element Dahil Değiştirme
const eski = document.querySelector("#eski");
console.log(eski.outerHTML); // "<div id='eski'>İçerik</div>"
// Elementin kendisi dahil değiştirilir
eski.outerHTML = "<section id='yeni'>Yepyeni İçerik</section>";
// ⚠️ eski referansı artık DOM'da olmayan bir elementi gösterir!Stil Değiştirme
Inline Stil: element.style
style özelliği, elementin inline stillerine erişim sağlar. CSS property isimleri camelCase formatında kullanılır.
const kutu = document.querySelector(".kutu");
// Tek stil değiştirme
kutu.style.backgroundColor = "#3498db";
kutu.style.color = "white";
kutu.style.padding = "20px";
kutu.style.borderRadius = "8px";
kutu.style.fontSize = "18px";
kutu.style.boxShadow = "0 4px 6px rgba(0, 0, 0, 0.1)";
// CSS property adı → JavaScript karşılığı
// background-color → backgroundColor
// font-size → fontSize
// border-radius → borderRadius
// z-index → zIndex
// margin-top → marginTop
// Stil okuma — sadece INLINE stillerini okur!
console.log(kutu.style.backgroundColor); // "#3498db"
console.log(kutu.style.width); // "" (CSS dosyasındaki stili okumaz!)
// Computed (hesaplanmış) stili okuma — TÜM kaynakları hesaplar
const computed = getComputedStyle(kutu);
console.log(computed.width); // "300px" (CSS dosyasından gelen dahil)
console.log(computed.backgroundColor); // "rgb(52, 152, 219)"
console.log(computed.display); // "block"
console.log(computed.marginTop); // "0px"
// Stil silme — boş string atar
kutu.style.backgroundColor = ""; // Inline stili kaldırır, CSS'e geri dönercssText ile Toplu Stil
// Tek tek yazmak yerine toplu stil
const kutu = document.querySelector(".kutu");
// ❌ Her satır ayrı stil ataması
kutu.style.width = "200px";
kutu.style.height = "200px";
kutu.style.background = "red";
// ✅ Tek seferde — ama mevcut inline stilleri SİLER
kutu.style.cssText = "width: 200px; height: 200px; background: red;";
// ✅ Mevcut stilleri koruyarak eklemek için
kutu.style.cssText += "; border: 2px solid black;";⚠️ Dikkat: Inline stiller, CSS dosyasındaki kuralları override eder (specificity açısından çok güçlüdür). Mümkün olduğunca stil değişikliklerini class ekleme/çıkarma ile yapın — daha temiz, daha sürdürülebilir ve CSS'in gücünü kullanır.
classList — Sınıf Yönetimi
classList, bir elementin CSS sınıflarını yönetmek için en temiz ve modern API'dir. Stil değişiklikleri için inline stil yerine class toggle etmek, profesyonel JavaScript yazımının temel prensibidir.
const kart = document.querySelector(".kart");
// ✅ add — Sınıf ekle (zaten varsa tekrar eklemez)
kart.classList.add("aktif");
kart.classList.add("golgeli", "yuvarlatilmis"); // Birden fazla
// ✅ remove — Sınıf kaldır (yoksa hata vermez)
kart.classList.remove("golgeli");
kart.classList.remove("aktif", "yuvarlatilmis"); // Birden fazla
// ✅ toggle — Varsa kaldır, yoksa ekle
kart.classList.toggle("aktif");
// İkinci parametre ile koşullu toggle
kart.classList.toggle("gece-modu", saatGeceMi()); // true ise ekle, false ise kaldır
// ✅ contains — Sınıf var mı kontrolü
if (kart.classList.contains("aktif")) {
console.log("Kart aktif!");
}
// ✅ replace — Bir sınıfı başkasıyla değiştir
kart.classList.replace("eski-tema", "yeni-tema");
// Tüm sınıfları listeleme
console.log(kart.classList); // DOMTokenList ["kart", "aktif", ...]
console.log(kart.classList.length); // Sınıf sayısı
// className — eski yöntem (tüm class string'ini değiştirir)
console.log(kart.className); // "kart aktif golgeli"
kart.className = "kart yeni-sinif"; // ⚠️ Diğer tüm sınıflar silinir!Pratik classList Kullanımları
// Dark mode toggle
const toggleBtn = document.querySelector("#tema-toggle");
toggleBtn.addEventListener("click", () => {
document.body.classList.toggle("dark-mode");
// Buton metnini güncelle
const isDark = document.body.classList.contains("dark-mode");
toggleBtn.textContent = isDark ? "☀️ Açık Mod" : "🌙 Koyu Mod";
});
// Accordion — tıklanan paneli aç/kapat
const paneller = document.querySelectorAll(".accordion-panel");
paneller.forEach(panel => {
panel.querySelector(".accordion-header").addEventListener("click", () => {
// Diğer panelleri kapat
paneller.forEach(p => {
if (p !== panel) p.classList.remove("acik");
});
// Bu paneli toggle et
panel.classList.toggle("acik");
});
});
// Form validasyon görsel geri bildirimi
function inputDogrula(input) {
if (input.validity.valid) {
input.classList.remove("hatali");
input.classList.add("gecerli");
} else {
input.classList.remove("gecerli");
input.classList.add("hatali");
}
}/* CSS tarafı — JavaScript sadece class toggle eder */
.kart {
transition: all 0.3s ease;
opacity: 0.7;
}
.kart.aktif {
opacity: 1;
transform: scale(1.02);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
}
.dark-mode {
background-color: #1a1a2e;
color: #eee;
}
.hatali {
border-color: #e74c3c;
background-color: #ffeaea;
}
.gecerli {
border-color: #27ae60;
background-color: #eafff0;
}Attribute (Öznitelik) Manipülasyonu
HTML elementlerinin attribute'ları (id, class, href, src, data-*, disabled, vb.) JavaScript ile okunabilir ve değiştirilebilir.
getAttribute / setAttribute
const link = document.querySelector("a.nav-link");
// Okuma
console.log(link.getAttribute("href")); // "/hakkinda"
console.log(link.getAttribute("target")); // "_blank" veya null
console.log(link.getAttribute("class")); // "nav-link aktif"
// Yazma
link.setAttribute("href", "/iletisim");
link.setAttribute("target", "_blank");
link.setAttribute("title", "İletişim sayfası");
// Silme
link.removeAttribute("target");
// Var mı kontrolü
if (link.hasAttribute("target")) {
console.log("Target attribute mevcut");
}Property vs Attribute
Bu ayrım kafa karıştırıcı olabilir ama önemlidir:
// HTML: <input type="text" value="başlangıç">
const input = document.querySelector("input");
// Attribute → HTML'deki başlangıç değeri
console.log(input.getAttribute("value")); // "başlangıç"
// Property → JavaScript nesnesinin mevcut değeri
console.log(input.value); // "başlangıç" (kullanıcı değiştirmediyse)
// Kullanıcı input'a "yeni değer" yazdıktan sonra:
console.log(input.getAttribute("value")); // "başlangıç" (HTML değişmedi!)
console.log(input.value); // "yeni değer" (property güncellendi)
// Diğer örnekler
const checkbox = document.querySelector('input[type="checkbox"]');
// checkbox.checked → boolean (property — mevcut durum)
// checkbox.getAttribute("checked") → string | null (attribute — başlangıç)Genel kural: Çoğu durumda property erişimini kullanın (doğrudan nokta notasyonu). getAttribute/setAttribute, özellikle data-* attribute'ları ve standart dışı attribute'lar için kullanın.
data-* Attribute'ları (Custom Data)
data-* attribute'ları, HTML elementlerine özel veri eklemenizi sağlar. JavaScript'ten dataset property'si ile erişilir.
// HTML:
// <div class="urun-kart"
// data-id="42"
// data-kategori="elektronik"
// data-fiyat="2999.99"
// data-stok-durumu="mevcut">
// iPhone 15
// </div>
const kart = document.querySelector(".urun-kart");
// dataset ile okuma — data- ön eki kaldırılır, camelCase'e çevrilir
console.log(kart.dataset.id); // "42" (her zaman string!)
console.log(kart.dataset.kategori); // "elektronik"
console.log(kart.dataset.fiyat); // "2999.99"
console.log(kart.dataset.stokDurumu); // "mevcut" (data-stok-durumu → stokDurumu)
// dataset ile yazma
kart.dataset.indirimli = "true"; // data-indirimli="true" eklenir
kart.dataset.fiyat = "2499.99"; // data-fiyat güncellenir
// Silme
delete kart.dataset.indirimli; // data-indirimli kaldırılır
// ⚠️ dataset değerleri HER ZAMAN string'dir!
const fiyat = parseFloat(kart.dataset.fiyat); // Sayıya çevirin
const id = parseInt(kart.dataset.id, 10);
// CSS'te data attribute seçimi
// [data-stok-durumu="mevcut"] { border-left: 3px solid green; }
// [data-stok-durumu="tukendi"] { opacity: 0.5; }Pratik: Sepet Butonu
// Ürün kartlarına sepet ekleme fonksiyonelliği
document.querySelectorAll(".sepete-ekle-btn").forEach(btn => {
btn.addEventListener("click", () => {
const urunKart = btn.closest(".urun-kart"); // En yakın parent kart
const urunBilgisi = {
id: parseInt(urunKart.dataset.id, 10),
isim: urunKart.dataset.isim,
fiyat: parseFloat(urunKart.dataset.fiyat),
};
sepeteEkle(urunBilgisi);
btn.textContent = "✅ Eklendi";
btn.disabled = true; // Butonu devre dışı bırak
});
});Element Oluşturma ve DOM'a Ekleme
Yeni elementler oluşturup DOM'a eklemek, dinamik web uygulamalarının temel taşıdır.
createElement + appendChild
// Yeni element oluştur
const yeniKart = document.createElement("div");
yeniKart.className = "kart";
yeniKart.id = "kart-42";
yeniKart.textContent = "Yeni ürün kartı";
yeniKart.dataset.id = "42";
// Daha karmaşık yapı
const makale = document.createElement("article");
makale.className = "blog-post";
const baslik = document.createElement("h2");
baslik.textContent = "JavaScript DOM Manipülasyonu";
const icerik = document.createElement("p");
icerik.textContent = "DOM, web sayfalarının programlama arayüzüdür...";
const etiketContainer = document.createElement("div");
etiketContainer.className = "etiketler";
["javascript", "dom", "web"].forEach(etiket => {
const span = document.createElement("span");
span.className = "etiket";
span.textContent = etiket;
etiketContainer.appendChild(span);
});
// Yapıyı birleştir
makale.appendChild(baslik);
makale.appendChild(icerik);
makale.appendChild(etiketContainer);
// DOM'a ekle
document.querySelector("#blog-listesi").appendChild(makale);insertAdjacentHTML — Esnek Konum
insertAdjacentHTML, belirli bir konuma HTML string'i ekler. innerHTML += ... gibi mevcut içeriği yeniden parse etmez — sadece yeni içeriği ekler.
const liste = document.querySelector("#gorev-listesi");
// Dört farklı konum:
// <!-- beforebegin -->
// <ul id="gorev-listesi">
// <!-- afterbegin -->
// <li>Mevcut görev</li>
// <!-- beforeend -->
// </ul>
// <!-- afterend -->
// Listenin BAŞINA ekle (ilk çocuk olarak)
liste.insertAdjacentHTML("afterbegin", '<li class="yeni">Birinci görev</li>');
// Listenin SONUNA ekle (son çocuk olarak)
liste.insertAdjacentHTML("beforeend", '<li class="yeni">Son görev</li>');
// Listenin ÖNÜNE ekle (kardeş olarak)
liste.insertAdjacentHTML("beforebegin", "<h3>Görevler</h3>");
// Listenin ARKASINA ekle (kardeş olarak)
liste.insertAdjacentHTML("afterend", "<p>Toplam: 5 görev</p>");append vs appendChild
const container = document.querySelector("#container");
// appendChild — tek bir Node ekler, eklenen node'u döndürür
const div = document.createElement("div");
const eklenen = container.appendChild(div); // eklenen === div
// append — birden fazla Node VE string ekleyebilir, void döndürür
container.append(
document.createElement("p"), // Node
"Düz metin", // String (text node olur)
document.createElement("span") // Node
);
// prepend — başa ekler (append'in karşılığı)
container.prepend(document.createElement("header"));
// before / after — kardeş olarak ekler
const referans = document.querySelector("#referans-element");
referans.before(document.createElement("div")); // Önüne
referans.after(document.createElement("div")); // Arkasına
// replaceWith — elementin kendisini değiştirir
const eski = document.querySelector("#eski");
const yeni = document.createElement("section");
yeni.textContent = "Yeni içerik";
eski.replaceWith(yeni);Element Kaldırma
// Modern yöntem — element.remove()
const silinecek = document.querySelector("#sil-beni");
silinecek.remove();
// Eski yöntem — parent üzerinden
const parent = document.querySelector("#liste");
const cocuk = parent.querySelector(".silinecek");
parent.removeChild(cocuk);
// Tüm çocukları silme
const container = document.querySelector("#container");
// Yöntem 1: innerHTML
container.innerHTML = ""; // Hızlı ama event listener'ları yok eder
// Yöntem 2: Döngü ile (event listener'ları korur — garbage collection)
while (container.firstChild) {
container.removeChild(container.firstChild);
}
// Yöntem 3: replaceChildren (modern)
container.replaceChildren(); // Tüm çocukları siler
container.replaceChildren(yeniElement1, yeniElement2); // Siler ve yenilerini eklerGerçek Dünya Örneği: Dinamik Ürün Kataloğu
Bu örnek, öğrendiğimiz tüm seçme ve değiştirme tekniklerini bir arada kullanır:
// Ürün verileri
const urunler = [
{ id: 1, isim: "MacBook Pro", fiyat: 54999, kategori: "bilgisayar", stok: 12 },
{ id: 2, isim: "iPhone 15", fiyat: 42999, kategori: "telefon", stok: 0 },
{ id: 3, isim: "AirPods Pro", fiyat: 8999, kategori: "aksesuar", stok: 45 },
{ id: 4, isim: "iPad Air", fiyat: 24999, kategori: "tablet", stok: 8 },
{ id: 5, isim: "Apple Watch", fiyat: 14999, kategori: "aksesuar", stok: 0 },
];
function urunKartiOlustur(urun) {
const kart = document.createElement("div");
kart.className = "urun-kart";
kart.dataset.id = urun.id;
kart.dataset.kategori = urun.kategori;
// Stok durumuna göre class
if (urun.stok === 0) {
kart.classList.add("tukenmis");
}
kart.innerHTML = `
<h3 class="urun-isim">${urun.isim}</h3>
<p class="urun-fiyat">${urun.fiyat.toLocaleString("tr-TR")} ₺</p>
<span class="urun-kategori">${urun.kategori}</span>
<p class="urun-stok">
${urun.stok > 0 ? `✅ Stokta (${urun.stok})` : "❌ Tükendi"}
</p>
<button class="sepet-btn" ${urun.stok === 0 ? "disabled" : ""}>
${urun.stok > 0 ? "🛒 Sepete Ekle" : "Stokta Yok"}
</button>
`;
return kart;
}
function kataloguRenderla(filtre = "hepsi") {
const container = document.querySelector("#urun-grid");
const fragment = document.createDocumentFragment();
const filtrelenmis = filtre === "hepsi"
? urunler
: urunler.filter(u => u.kategori === filtre);
// Sayaç güncelle
const sayac = document.querySelector("#urun-sayac");
sayac.textContent = `${filtrelenmis.length} ürün gösteriliyor`;
filtrelenmis.forEach(urun => {
fragment.appendChild(urunKartiOlustur(urun));
});
container.replaceChildren(fragment);
// Aktif filtre butonunu güncelle
document.querySelectorAll(".filtre-btn").forEach(btn => {
btn.classList.toggle("aktif", btn.dataset.kategori === filtre);
});
}
// Filtre butonları
document.querySelectorAll(".filtre-btn").forEach(btn => {
btn.addEventListener("click", () => {
kataloguRenderla(btn.dataset.kategori);
});
});
// İlk yükleme
kataloguRenderla();<!-- HTML yapısı -->
<div class="katalog">
<div class="filtreler">
<button class="filtre-btn aktif" data-kategori="hepsi">Tümü</button>
<button class="filtre-btn" data-kategori="bilgisayar">Bilgisayar</button>
<button class="filtre-btn" data-kategori="telefon">Telefon</button>
<button class="filtre-btn" data-kategori="tablet">Tablet</button>
<button class="filtre-btn" data-kategori="aksesuar">Aksesuar</button>
</div>
<p id="urun-sayac"></p>
<div id="urun-grid"></div>
</div>Bu örnekte:
querySelector/querySelectorAllile element seçimicreateElement+innerHTMLile element oluşturmaclassList.add/toggle/containsile class yönetimidatasetile data attribute okuma/yazmaDocumentFragmentile toplu DOM eklemereplaceChildrenile temiz güncellemetextContentile güvenli metin güncellemedisabledattribute ile buton kontrolü
Yaygın Hatalar
Hata 1: querySelector'da # veya . Unutmak
// ❌ ID için # işaretini unutmak
document.querySelector("ana-baslik"); // Etiket arar, bulamaz → null
// ✅ Doğrusu
document.querySelector("#ana-baslik"); // ID ile seçer
// ❌ Class için . işaretini unutmak
document.querySelector("kart"); // <kart> etiketi arar
// ✅ Doğrusu
document.querySelector(".kart"); // Class ile seçerHata 2: null Kontrolü Yapmamak
// ❌ Element bulunamazsa patlar
const btn = document.querySelector("#olmayan-buton");
btn.addEventListener("click", handler); // TypeError: Cannot read properties of null
// ✅ Null kontrolü yapın
const btn = document.querySelector("#olmayan-buton");
if (btn) {
btn.addEventListener("click", handler);
}
// ✅ veya optional chaining (sadece okuma için)
const text = document.querySelector("#yok")?.textContent ?? "Varsayılan";Hata 3: innerHTML += ile İçerik Ekleme
// ❌ innerHTML += tüm içeriği yeniden parse eder
// Mevcut event listener'lar KAYBOLUR!
liste.innerHTML += "<li>Yeni</li>";
// ✅ insertAdjacentHTML — sadece yeni kısım parse edilir
liste.insertAdjacentHTML("beforeend", "<li>Yeni</li>");
// ✅ veya createElement + appendChild
const li = document.createElement("li");
li.textContent = "Yeni";
liste.appendChild(li);Özet
🔹 `querySelector` ve `querySelectorAll`, CSS selector gücüyle element seçmek için modern ve yeterli yöntemlerdir.
querySelectorAllstatik bir NodeList döndürür.🔹 `textContent` güvenli metin işleme için, `innerHTML` HTML parse gerektiren durumlar için kullanılır. Kullanıcı girdisini asla
innerHTML'e yazmayın — XSS açığı oluşur.🔹 Stil değişikliklerini inline `style` yerine `classList` ile yapın:
.add(),.remove(),.toggle(),.contains()yöntemleri temiz ve sürdürülebilir kod sağlar.🔹 `data-*` attribute'ları (
dataset) HTML elementlerine özel veri bağlamak için idealdir. Değerler her zaman string'dir — sayıya çevirmeyi unutmayın.🔹 Element oluşturmada
createElement+appendChildveyainsertAdjacentHTMLkullanın. `innerHTML +=` mevcut event listener'ları yok eder — kaçının.🔹 Toplu DOM eklemelerinde `DocumentFragment` kullanarak tek bir reflow ile binlerce element ekleyin.
AI Asistan
Sorularını yanıtlamaya hazır