Signatur
Beschreibung
Die Eigenschaft addedNodes eines MutationRecord enthält alle Knoten, die durch eine einzelne Mutation als Kinder in den Zielknoten (record.target) eingefügt wurden. Gefüllt ist sie nur bei Datensätzen vom Typ "childList". Bei "attributes" und "characterData" ist sie eine leere NodeList.
Typische Einsatzfälle: Sie wollen dynamisch nachgeladene Inhalte erkennen und verarbeiten, zum Beispiel Widgets initialisieren, Bilder für Lazy-Loading anmelden, Inhalte von Drittanbieter-Skripten überwachen oder in einer Single-Page-App auf neu gerenderte Komponenten reagieren. Mit subtree: true meldet der Observer auch Einfügungen in tieferen Ebenen. Pro Datensatz ist dann target das jeweilige direkte Elternelement.
Wichtig: In der Liste stehen nur die direkt eingefügten Knoten, nicht deren Nachfahren. Fügen Sie ein <div> mit verschachtelten Elementen ein, erscheint nur das <div> selbst. Die Nachfahren müssen Sie mit querySelectorAll() selbst durchsuchen. Neben Elementen können auch Text- und Kommentarknoten enthalten sein. Filtern Sie deshalb bei Bedarf nach node.nodeType === Node.ELEMENT_NODE.
Rückgabewert
NodeList der eingefügten Knoten. Sie ist leer, wenn keine Knoten eingefügt wurden oder der Datensatz nicht vom Typ "childList" ist.Beispiele
Neu eingefügte Listeneinträge protokollieren
const list = document.createElement('ul');
document.body.append(list);
const observer = new MutationObserver((records) => {
for (const record of records) {
for (const node of record.addedNodes) {
if (node.nodeType === Node.ELEMENT_NODE) {
console.log('Hinzugefügt:', node.tagName, node.textContent);
}
}
}
});
observer.observe(list, { childList: true });
const li = document.createElement('li');
li.textContent = 'Erster Eintrag';
list.append(li);
Dynamisch nachgeladene Widgets samt Nachfahren initialisieren
const initWidget = (el) => {
if (el.dataset.ready) return;
el.dataset.ready = 'true';
console.log('Widget initialisiert:', el.id);
};
const observer = new MutationObserver((records) => {
for (const { addedNodes } of records) {
for (const node of addedNodes) {
if (!(node instanceof Element)) continue;
// Der Knoten selbst ...
if (node.matches('[data-widget]')) initWidget(node);
// ... und alle verschachtelten Widgets
node.querySelectorAll('[data-widget]').forEach(initWidget);
}
}
});
observer.observe(document.body, { childList: true, subtree: true });
const wrapper = document.createElement('section');
wrapper.innerHTML = '<div data-widget id="chart"></div><div data-widget id="map"></div>';
document.body.append(wrapper);
Auf ein bestimmtes Element warten (Promise)
const waitForElement = (selector, root = document.body) =>
new Promise((resolve) => {
const existing = root.querySelector(selector);
if (existing) return resolve(existing);
const observer = new MutationObserver((records) => {
for (const record of records) {
for (const node of record.addedNodes) {
if (!(node instanceof Element)) continue;
const match = node.matches(selector) ? node : node.querySelector(selector);
if (match) {
observer.disconnect();
resolve(match);
return;
}
}
}
});
observer.observe(root, { childList: true, subtree: true });
});
const run = async () => {
setTimeout(() => {
const btn = document.createElement('button');
btn.className = 'cookie-accept';
document.body.append(btn);
}, 500);
const button = await waitForElement('.cookie-accept');
console.log('Gefunden:', button.className);
};
run();
// Wichtig · Fallstricke
- Nur direkte Kinder: Nachfahren eingefügter Knoten stehen nicht in
addedNodes. Das gilt auch dann, wenn Sie mitinnerHTMLganze Bäume einfügen. Die Nachfahren müssen Sie selbst mitquerySelectorAll()durchsuchen. - Nicht nur Elemente: Die Liste kann auch Text- und Kommentarknoten enthalten, etwa Leerraum aus
innerHTML. Aufrufe wiematches()scheitern auf Textknoten. Prüfen Sie deshalb vorhernodeTypeoderinstanceof Element. - Verschobene Knoten: Wird ein vorhandener Knoten mit
append()oderinsertBefore()verschoben, erscheint er inremovedNodesdes alten und inaddedNodesdes neuen Elternelements. - Knoten evtl. schon wieder entfernt: Die Callbacks laufen asynchron als Mikrotask. Zu diesem Zeitpunkt kann ein Knoten aus
addedNodesbereits wieder aus dem DOM entfernt sein. Prüfen Sie im Zweifelnode.isConnected. - Voraussetzung: Die Liste wird nur befüllt, wenn der Observer mit
childList: truegestartet wurde. - Leistung: Mit
subtree: trueaufdocument.bodykann der Callback sehr oft feuern. Halten Sie die Verarbeitung schlank, und rufen Siedisconnect()auf, sobald Sie den Observer nicht mehr brauchen. - Kompatibilität: Wird von allen modernen Browsern unterstützt.
for...ofüberNodeListfunktioniert nicht im Internet Explorer.