Signatur
Beschreibung
Die schreibgeschützte Eigenschaft attributeName eines MutationRecord gibt an, welches Attribut am beobachteten Element geändert wurde. Sie ist nur gefüllt, wenn record.type === "attributes" ist. Bei childList- und characterData-Mutationen ist der Wert null.
Zurückgegeben wird der lokale Name des Attributs, also ohne Namensraum-Präfix. Bei einem namensraumbehafteten Attribut wie xlink:href enthält attributeName nur "href", den Namensraum liefert attributeNamespace. Den alten Wert bekommt man über oldValue, allerdings nur, wenn der Observer mit attributeOldValue: true registriert wurde. Den neuen Wert liest man direkt am Element aus, z. B. mit record.target.getAttribute(record.attributeName).
Typische Einsatzfälle sind das Reagieren auf Zustandsattribute wie class, aria-expanded, disabled oder data-*, das Synchronisieren von Web Components mit externen Attributänderungen und das Protokollieren von DOM-Änderungen durch Drittskripte.
Rückgabewert
"class") oder null, wenn die Mutation nicht vom Typ attributes ist.Beispiele
Geänderte Attribute protokollieren
const box = document.createElement('div');
document.body.append(box);
const observer = new MutationObserver((records) => {
for (const record of records) {
if (record.type === 'attributes') {
const neu = record.target.getAttribute(record.attributeName);
console.log(`${record.attributeName}: "${record.oldValue}" → "${neu}"`);
}
}
});
observer.observe(box, { attributes: true, attributeOldValue: true });
box.className = 'aktiv';
box.dataset.status = 'geladen';
Nur bestimmte Attribute beobachten (attributeFilter)
const button = document.createElement('button');
document.body.append(button);
const observer = new MutationObserver((records) => {
records.forEach(({ attributeName, target }) => {
if (attributeName === 'aria-expanded') {
const offen = target.getAttribute('aria-expanded') === 'true';
console.log(offen ? 'Menü geöffnet' : 'Menü geschlossen');
}
});
});
observer.observe(button, {
attributeFilter: ['aria-expanded', 'disabled']
});
button.setAttribute('aria-expanded', 'true');
button.title = 'Wird ignoriert'; // nicht im Filter
attributeName ist null bei childList-Mutationen
const liste = document.createElement('ul');
document.body.append(liste);
const observer = new MutationObserver((records) => {
records.forEach((r) => console.log(r.type, r.attributeName));
});
observer.observe(liste, { childList: true, attributes: true });
liste.append(document.createElement('li'));
liste.id = 'hauptliste';
Namensraum-Attribute in SVG
const NS_SVG = 'http://www.w3.org/2000/svg';
const NS_XLINK = 'http://www.w3.org/1999/xlink';
const use = document.createElementNS(NS_SVG, 'use');
const observer = new MutationObserver(([record]) => {
console.log(record.attributeName, record.attributeNamespace);
});
observer.observe(use, { attributes: true });
use.setAttributeNS(NS_XLINK, 'xlink:href', '#icon');
// Wichtig · Fallstricke
- Nur bei
type === "attributes"gesetzt: Prüfen Sie vor der Nutzung immer den Typ, sonst arbeiten Sie mitnull. - Lokaler Name ohne Präfix: Bei
xlink:hrefsteht inattributeNamenur"href". Zur eindeutigen Unterscheidung zusätzlichattributeNamespaceauswerten. - Kein neuer Wert im Record: Der aktuelle Wert muss am Element gelesen werden. Weil Mutationen gebündelt und asynchron (als Microtask) ausgeliefert werden, kann das Attribut bis dahin schon mehrfach geändert worden sein. Jeder Record gehört zu einer Änderung,
getAttribute()liefert aber immer den Endzustand. oldValuebraucht eine Option: OhneattributeOldValue: trueistoldValueimmernull.- Gleicher Wert erzeugt trotzdem einen Record: Auch
setAttribute('x', 'a')auf ein Attribut, das schon'a'ist, löst eine Mutation aus. Wenn nötig,oldValuemit dem neuen Wert vergleichen. - Performance: Mit
attributeFilterbegrenzen Sie die Beobachtung auf relevante Attribute. Das spart Rückrufe, besonders mitsubtree: true. - Wird in allen modernen Browsern unterstützt. In Web Components ist für eigene Attribute oft
attributeChangedCallbackmitobservedAttributesdie einfachere Lösung.