的 MutationObserver 接口,可以在 DOM 被修改时异步执行回调。使 用 MutationObserver 可以观察整个文档、 DOM 树的一部分,或某个元素。此外还可以观察元素属性、子节点、文本,或者前三者任意组合的变化。
MutationObserver 的实例要通过调用 MutationObserver 构造函数并传入一个回调函数来创建:
let observer = new MutationObserver(() => console.log('DOM was mutated!'));
新创建的 MutationObserver 实例不会关联 DOM 的任何部分。要把这个 observer 与 DOM 关 联起来,需要使用 observe()方法。这个方法接收两个必需的参数:要观察其变化的 DOM 节点,以及
一个 MutationObserverInit 对象。 MutationObserverInit 对象用于控制观察哪些方面的变化,是一个键/值对形式配置选项的字典。
例如,下面的代码会创建一个观察者( observer )并配置它观察 <body>
元素上的属性变化
let observer = new MutationObserver(() =>
console.log('<body> attributes changed'),
);
observer.observe(document.body, { attributes: true });
每个回调都会收到一个 MutationRecord 实例的数组。 MutationRecord 实例包含的信息包括发 生了什么变化,以及 DOM 的哪一部分受到了影响。因为回调执行之前可能同时发生多个满足观察条件 的事件,所以每次执行回调都会传入一个包含按顺序入队的 MutationRecord 实例的数组。
let observer = new MutationObserver(mutationRecords =>
console.log(mutationRecords),
);
observer.observe(document.body, { attributes: true });
document.body.className = 'foo';
document.body.className = 'bar';
document.body.className = 'baz';
// [MutationRecord, MutationRecord, MutationRecord]
target | 被修改影响的目标节点 |
type | 字符串, 表示变化的类型: "attributes"、"characterData"或 "childList" |
oldValue | 如果在 MutationObserverInit 对象中启用( attributeOldValue 或 characterData OldValue 为 true ), "attributes"或 |
"characterData"的变化事件会设置这个属性为被替代的值 "childList"类型的变化始终将这个属性设置为 null | |
attributeName | 对于"attributes"类型的变化,这里保存被修改属性的名字其它变化事件会将这个属性设置为 null |
attributeNamespace | 对于使用了命名空间的"attributes"类型的变化,这里保存被修改属性的名字其它变化事件会将这个属性设置为 null |
addedNodes | 对于"childList"类型的变化,返回包含变化中添加节点的 NodeList 默认为空 NodeList |
removedNodes | 对于"childList"类型的变化,返回包含变化中删除节点的 NodeList 默认为空 NodeList |
previousSibling | 对于"childList"类型的变化,返回变化节点的前一个同胞 Node 默认为 null |
nextSibling | 对于"childList"类型的变化,返回变化节点的后一个同胞 Node 默认为 null |
let observer = new MutationObserver((mutationRecords, mutationObserver) =>
console.log(mutationRecords, mutationObserver),
);
observer.observe(document.body, {
attributes: true,
});
document.body.className = 'foo';
// [MutationRecord], MutationObserver
默认情况下,只要被观察的元素不被垃圾回收, MutationObserver 的回调就会响应 DOM 变化事 件,从而被执行。要提前终止执行回调,可以调用 disconnect()方法。下面的例子演示了同步调用 disconnect()之后,不仅会停止此后变化事件的回调,也会抛弃已经加入任务队列要异步执行的回调 。
let observer = new MutationObserver(() =>
console.log('<body> attributes changed'),
);
observer.observe(document.body, { attributes: true });
document.body.className = 'foo';
observer.disconnect();
document.body.className = 'bar';
// (没有日志输出)
多次调用 observe()
方法,可以复用一个 MutationObserver
对象观察多个不同的目标节点。此 时,MutationRecord
的 target 属性可以标识发生变化事件的目标节点。
let observer = new MutationObserver(mutationRecords =>
console.log(mutationRecords.map(x => x.target)),
); // 向页面主体添加两个子节点
let childA = document.createElement('div'),
childB = document.createElement('span');
document.body.appendChild(childA);
document.body.appendChild(childB);
// 观察两个子节点
observer.observe(childA, {
attributes: true,
});
observer.observe(childB, { attributes: true }); // 修改两个子节点的属性
childA.setAttribute('foo', 'bar');
childB.setAttribute('foo', 'bar');
// [<div>, ]
调用 disconnect()并不会结束 MutationObserver 的生命。还可以重新使用这个观察者,再将 它关联到新的目标节点。
let observer = new MutationObserver(() =>
console.log('<body> attributes changed '),
);
observer.observe(document.body, { attributes: true }); // 这行代码会触发变化事件
document.body.setAttribute('foo', 'bar');
setTimeout(() => {
observer.disconnect(); // 这行代码不会触发变化事件
document.body.setAttribute('bar', 'baz');
}, 0);
setTimeout(() => {
// Reattach
observer.observe(document.body, {
attributes: true,
}); // 这行代码会触发变化事件
document.body.setAttribute('baz', 'qux');
}, 0); // <body> attributes changed
// <body> attributes changed