Signatur
Beschreibung
Die Eigenschaft removedNodes eines MutationRecord enthält alle Kindknoten, die bei einer einzelnen DOM-Änderung aus dem Zielknoten (record.target) entfernt wurden. Befüllt wird sie nur bei Datensätzen vom Typ "childList". Den Observer muss man dafür mit der Option childList: true starten, optional mit subtree: true, wenn auch Änderungen in tieferen Ebenen erfasst werden sollen.
Typische Einsatzfälle sind Aufräumarbeiten, wenn Elemente aus dem DOM verschwinden. Dazu gehört zum Beispiel, Event-Listener, Timer oder Instanzen von Drittbibliotheken freizugeben, ein Widget zu zerstören, das Entfernen eines Elements zu protokollieren oder einen Zustand zu synchronisieren, etwa einen Zähler für Listeneinträge.
Die NodeList ist statisch. Sie ändert sich also nicht, wenn das DOM danach weiter verändert wird. Sie kann jede Art von Knoten enthalten, also auch Textknoten (Node.TEXT_NODE) und Kommentare. Wurde nichts entfernt, etwa bei "attributes"- oder "characterData"-Datensätzen, ist die Liste leer, aber nie null. Zusammen mit previousSibling und nextSibling lässt sich genau bestimmen, an welcher Stelle die Knoten entfernt wurden.
Rückgabewert
NodeList der entfernten Knoten. Sie ist leer (length === 0), wenn bei dieser Mutation keine Knoten entfernt wurden.Beispiele
Entfernte Listeneinträge protokollieren
const liste = document.querySelector('#todo-liste');
const observer = new MutationObserver((records) => {
for (const record of records) {
if (record.type !== 'childList') continue;
for (const node of record.removedNodes) {
// Nur Elemente berücksichtigen, keine Text- oder Kommentarknoten
if (node.nodeType === Node.ELEMENT_NODE) {
console.log('Entfernt:', node.textContent.trim());
}
}
}
});
observer.observe(liste, { childList: true });
// Mutation auslösen
liste.firstElementChild?.remove();
Aufräumen, wenn ein Widget aus dem DOM verschwindet
const widgets = new WeakMap();
const initWidget = (el) => {
const id = setInterval(() => { el.textContent = new Date().toLocaleTimeString(); }, 1000);
widgets.set(el, () => clearInterval(id));
};
document.querySelectorAll('.uhr').forEach(initWidget);
const observer = new MutationObserver((records) => {
for (const { removedNodes } of records) {
removedNodes.forEach((node) => {
if (!(node instanceof Element)) return;
// Auch verschachtelte Widgets im entfernten Teilbaum finden
const betroffen = [node, ...node.querySelectorAll('.uhr')];
for (const el of betroffen) {
const cleanup = widgets.get(el);
if (cleanup && !el.isConnected) {
cleanup();
widgets.delete(el);
console.log('Timer gestoppt für', el);
}
}
});
}
});
observer.observe(document.body, { childList: true, subtree: true });
Hinzugefügte und entfernte Knoten zählen
const container = document.createElement('div');
container.innerHTML = '<p>A</p><p>B</p>';
document.body.append(container);
const observer = new MutationObserver((records) => {
const entfernt = records.reduce((sum, r) => sum + r.removedNodes.length, 0);
const hinzugefuegt = records.reduce((sum, r) => sum + r.addedNodes.length, 0);
console.log({ entfernt, hinzugefuegt });
});
observer.observe(container, { childList: true });
// innerHTML ersetzt alle Kinder: 2 entfernt, 1 hinzugefügt
container.innerHTML = '<p>C</p>';
// Wichtig · Fallstricke
- Nur bei
childList: OhnechildList: trueinobserve()bleibtremovedNodesimmer leer. Bei Attribut- oder Textänderungen ist die Liste ebenfalls leer. - Verschieben zählt als Entfernen:
appendChild()oderinsertBefore()mit einem Knoten, der schon im DOM hängt, erzeugt einen Datensatz mitremovedNodesfür die alte Position. Deshalb vor dem Aufräumennode.isConnectedprüfen, damit verschobene Elemente nicht versehentlich zerstört werden. - Nur direkte Kinder: In der Liste stehen nur die Wurzeln der entfernten Teilbäume. Nachfahren darin muss man selbst suchen, zum Beispiel mit
querySelectorAll(). Auch mitsubtree: trueerzeugt das Entfernen eines Elternknotens keine eigenen Datensätze für seine Kinder. - Textknoten: Durch Leerraum im HTML landen oft Textknoten in der Liste. Deshalb nach
nodeTypeoderinstanceof Elementfiltern. - Asynchron und gebündelt: Der Callback läuft als Microtask und erhält mehrere Datensätze auf einmal. Rechenintensive Arbeit pro Knoten kann bei großen DOM-Änderungen die Leistung bremsen.
- Die Eigenschaft ist schreibgeschützt und wird von allen modernen Browsern unterstützt. Das veraltete
DOMNodeRemoved-Mutation-Event ist abgekündigt und sollte nicht mehr verwendet werden.