26.12.2025

JavaScript’te MutationObserver ile DOM Değişikliklerini İzleme: Widget ve Eklentiler İçin Pratik Rehber

Dinamik sayfalarda DOM değişikliklerini MutationObserver ile yakalayıp güvenli ve performanslı şekilde tepki verin.

Modern web sayfaları (SPA’ler, CMS’ler, A/B test araçları) DOM’u sürekli değiştirir. Bir widget geliştiriyorsanız “buton sonradan eklendi, event bağlanmadı” ya da “render tekrarlandı, iki kez çalıştı” gibi sorunlar kaçınılmazdır. Bu noktada MutationObserver, DOM’daki değişimleri izleyip doğru anda aksiyon almanızı sağlar.

MutationObserver ne işe yarar?

  • Yeni eklenen/çıkarılan elementleri yakalar
  • Attribute değişikliklerini izler (ör. data-*, class)
  • Metin değişikliklerini (characterData) takip edebilir

Kullanım alanları:

  • Üçüncü parti script/widget entegrasyonları
  • Sonsuz scroll ile gelen içerikte “yeni kartlara etiket basma”
  • CMS üzerinde sonradan yüklenen formları otomatik zenginleştirme

Temel kullanım

Aşağıdaki örnek, #feed içine sonradan eklenen .product-card öğelerini bulup bir kez “işaretler”:

const feed = document.querySelector('#feed');

function enhanceCard(card) {
  if (card.dataset.enhanced === '1') return; // idempotent
  card.dataset.enhanced = '1';

  // Örnek: karta rozet ekle
  const badge = document.createElement('span');
  badge.className = 'badge';
  badge.textContent = 'Yeni';
  card.prepend(badge);
}

const observer = new MutationObserver((mutations) => {
  for (const m of mutations) {
    // childList: eklenen/çıkarılan düğümler
    for (const node of m.addedNodes) {
      if (!(node instanceof Element)) continue;

      // Node’un kendisi kart olabilir
      if (node.matches('.product-card')) enhanceCard(node);

      // Ya da içinde kartlar olabilir
      node.querySelectorAll?.('.product-card').forEach(enhanceCard);
    }
  }
});

observer.observe(feed, {
  childList: true,
  subtree: true
});

Neden dataset.enhanced? MutationObserver aynı element için birden fazla tetiklenebilir (yeniden render, taşıma, vs.). Bu küçük “idempotent” kontrol, iki kez rozet basma gibi hataları engeller.

Attribute izleme: class/data değişince tepki ver

Örneğin bir modal açıldığında body’ye .modal-open ekleniyor olabilir. Bu durumu dinleyip scroll kilidi ya da ölçüm alabilirsiniz:

const obs = new MutationObserver((mutations) => {
  for (const m of mutations) {
    if (m.type === 'attributes' && m.attributeName === 'class') {
      const isOpen = document.body.classList.contains('modal-open');
      console.log('Modal durumu:', isOpen);
    }
  }
});

obs.observe(document.body, {
  attributes: true,
  attributeFilter: ['class']
});

Performans ipuçları (kritik)

MutationObserver güçlüdür; yanlış kullanılırsa gereksiz iş üretir.

  1. İzleme kapsamını daraltın: document yerine mümkünse hedef container.
  2. attributeFilter kullanın: Her attribute değişimini dinlemeyin.
  3. Batch işlem yapın: Çok sayıda mutation gelirse tek seferde işleyin.

Basit bir “batch” örneği:

let pending = new Set();
let scheduled = false;

function scheduleFlush() {
  if (scheduled) return;
  scheduled = true;
  queueMicrotask(() => {
    scheduled = false;
    for (const el of pending) enhanceCard(el);
    pending.clear();
  });
}

const observer2 = new MutationObserver((mutations) => {
  for (const m of mutations) {
    for (const node of m.addedNodes) {
      if (!(node instanceof Element)) continue;
      node.querySelectorAll?.('.product-card').forEach((el) => pending.add(el));
    }
  }
  scheduleFlush();
});

Ne zaman kullanmamalı?

  • Kendi kodunuz elementleri ekliyorsa, doğrudan o noktada fonksiyon çağırmak daha net olabilir.
  • Sürekli değişen devasa DOM alanlarında (ör. çok yoğun animasyon/virtual list) maliyet artabilir.

Sonuç

MutationObserver, özellikle kontrol etmediğiniz DOM değişimlerine uyum sağlamak için ideal: eklenti, widget ve dinamik içerik senaryolarında “sonradan gelen element” problemini temizce çözer. Doğru scope ve idempotent yaklaşım ile hem sağlam hem de performanslı bir çözüm elde edersiniz.