我有一些类似以下的代码,
const observer = new MutationObserver(records => {
for (const record of records) {
if (record.type !== 'attributes') continue
handleAttrChange(
record.attributeName!,
record.oldValue,
record.target.attributes.getNamedItem(record.attributeName).value,
)
}
})
其中handleAttrChange
参数是属性名称,旧值和新值。
但是,正如您所知,第三个参数传递给handleAttrChange
,
record.target.attributes.getNamedItem(record.attributeName!)!.value
始终将是最新的属性值,not我们正在迭代的特定突变记录的“新值”(即不是在发生突变的时间)。
我们如何获得每个突变的“新值”,就像在每个突变发生时所观察到的那样?
我认为MutationObserver
不可能。 MutationRecord中的任何内容都不会暴露新值,并且由于MuationObserver在微任务中运行,并且更改后未完全同步,因此可以从观察者回调内的元素检索的值可能已更改< [之后如您所见,触发观察者的更改。
const observer = new MutationObserver(records => {
for (const record of records) {
if (record.type !== 'attributes') continue
console.log(div.dataset.foo);
console.log(record);
}
});
observer.observe(div, { attributes: true });
div.setAttribute('data-foo', 'foo');
div.setAttribute('data-foo', 'bar');
<div id="div"></div>
虽然可以使用观察者(侦听元素上的synchronous
DOMAttrModified
事件),但不推荐使用它们,而且速度很慢。如果您知道如何更改属性,则可以修补该方法,以使其首先通过您的own
逻辑。例如,使用setAttribute
: div.setAttribute = (...args) => {
console.log(`Setting ${args[0]} from ${div.getAttribute(args[0])} to ${args[1]}`);
return HTMLElement.prototype.setAttribute.apply(div, args);
};
div.setAttribute('data-foo', 'foo');
div.setAttribute('data-foo', 'bar');
<div id="div"></div>
const observer = new MutationObserver(records => {
let lastAttributeValues = {}
let name = ''
for (const record of records) {
if (record.type !== 'attributes') continue
name = record.attributeName
if (lastAttributeValues[name] === undefined) {
lastAttributeValues[name] = record.oldValue
continue
}
handleAttributeChange(name, lastAttributeValues[name], record.oldValue)
lastAttributeValues[name] = record.oldValue
}
for (const name in lastAttributeValues) {
handleAttributeChange(name, lastAttributeValues[name], el.attributes.getNamedItem(name).value)
}
})
它的作用是,因为我们知道我们可以按顺序获得突变,并且在迭代的过程中拥有给定属性的所有属性值,所以它仅跟踪先前和当前的属性值(按属性名称)并触发handleAttributeChange
以及每个先前的值和当前值。