Signatur
Beschreibung
Mit observe() meldest du einen MutationObserver an einem Zielknoten an. Ab diesem Moment sammelt der Browser alle passenden Änderungen als MutationRecord-Objekte und übergibt sie gebündelt an den Callback, der im Konstruktor angegeben wurde. Die Zustellung erfolgt asynchron als Microtask, also nach dem aktuell laufenden Skript, aber vor dem nächsten Rendern.
Über das options-Objekt legst du fest, was beobachtet wird: Hinzufügen und Entfernen von Kindknoten (childList), Attributänderungen (attributes), Änderungen an Textknoten (characterData) und ob der gesamte Unterbaum einbezogen wird (subtree). Mindestens eine der Optionen childList, attributes oder characterData muss am Ende true sein, sonst wirft die Methode einen TypeError.
Typische Einsatzfälle sind: auf dynamisch nachgeladene Inhalte reagieren (z. B. von Drittanbieter-Skripten), Widgets initialisieren, sobald ihr Element im DOM auftaucht, Attributänderungen wie class oder aria-* verfolgen oder Editoren mit contenteditable überwachen. Ein Observer kann mehrere Ziele beobachten, indem du observe() mehrfach aufrufst. Wird derselbe Knoten erneut beobachtet, ersetzen die neuen Optionen die alten.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $target Pflicht | Node | Der DOM-Knoten (Element, Textknoten, Document …), der beobachtet werden soll. Mit subtree: true gilt die Beobachtung auch für alle Nachfahren. |
|
| $options | MutationObserverInit | {} | Konfigurationsobjekt mit folgenden Eigenschaften:
childList, attributes oder characterData muss (direkt oder implizit) aktiv sein. |
Beispiele
Neu eingefügte Listeneinträge erkennen
const liste = document.querySelector('#nachrichten');
const observer = new MutationObserver((records) => {
for (const record of records) {
for (const node of record.addedNodes) {
if (node.nodeType === Node.ELEMENT_NODE) {
console.log('Neuer Eintrag:', node.textContent);
}
}
}
});
observer.observe(liste, { childList: true });
// Simuliert nachgeladenen Inhalt
const li = document.createElement('li');
li.textContent = 'Hallo Welt';
liste.append(li);
Bestimmte Attribute mit altem Wert verfolgen
const button = document.querySelector('#menue-button');
const observer = new MutationObserver((records) => {
for (const { attributeName, oldValue, target } of records) {
console.log(`${attributeName}: ${oldValue} → ${target.getAttribute(attributeName)}`);
}
});
// attributes: true ist durch attributeFilter implizit gesetzt
observer.observe(button, {
attributeFilter: ['aria-expanded', 'class'],
attributeOldValue: true
});
button.setAttribute('aria-expanded', 'true');
Warten, bis ein Element im DOM erscheint (Promise-Helfer)
const warteAufElement = (selector, root = document.body) =>
new Promise((resolve) => {
const vorhanden = root.querySelector(selector);
if (vorhanden) return resolve(vorhanden);
const observer = new MutationObserver(() => {
const el = root.querySelector(selector);
if (el) {
observer.disconnect(); // Beobachtung beenden, Speicher freigeben
resolve(el);
}
});
observer.observe(root, { childList: true, subtree: true });
});
const main = async () => {
const widget = await warteAufElement('.chat-widget');
console.log('Widget gefunden:', widget.className);
};
main();
setTimeout(() => {
const div = document.createElement('div');
div.className = 'chat-widget';
document.body.append(div);
}, 500);
Textänderungen in einem contenteditable-Bereich
const editor = document.querySelector('[contenteditable]');
const observer = new MutationObserver((records) => {
const textAenderungen = records.filter((r) => r.type === 'characterData');
console.log(`${textAenderungen.length} Textänderung(en)`);
});
observer.observe(editor, {
characterData: true,
characterDataOldValue: true,
childList: true,
subtree: true
});
// Später, z. B. beim Verlassen der Seite:
// observer.disconnect();
// Wichtig · Fallstricke
- TypeError: Wirft einen Fehler, wenn weder
childList,attributesnochcharacterDataaktiv ist, oder wennattributeOldValue/attributeFiltermit explizitemattributes: falsekombiniert wird (analog fürcharacterDataOldValue). - Performance:
{ childList: true, subtree: true }aufdocument.bodykann auf großen, dynamischen Seiten sehr viele Records erzeugen. Beobachte möglichst eng begrenzte Knoten, nutzeattributeFilterund halte den Callback schlank. - Endlosschleifen: Änderst du im Callback das beobachtete DOM, löst das erneut Mutationen aus. Vorher
disconnect()aufrufen oder Änderungen per Bedingung absichern. - Asynchron: Der Callback läuft als Microtask, mehrere Änderungen werden gebündelt. Wer synchron ausstehende Records braucht, nutzt
takeRecords(). - Entfernte Knoten: Bei
subtree: truewerden Änderungen in einem entfernten Teilbaum weiterhin gemeldet, bis der Observer die entfernten Knoten nicht mehr verfolgt (bis zur nächsten Zustellung). - Observer werden nicht automatisch beendet – mit
disconnect()aufräumen, um Speicherlecks zu vermeiden. Shadow DOM-Inhalte werden nicht über den Host erfasst; denShadowRootseparat beobachten. - Kompatibilität: In allen modernen Browsern verfügbar (ab IE 11); ersetzt die veralteten Mutation Events wie
DOMNodeInserted.