不久前添加到 DOM 规范中的 MutationObserver 接口,可以在 DOM 被修改时异步执行回调。使用 MutationObserver 可以观察整个文档、DOM 树的一部分,或某个元素。此外还可以观察元素属性、子节点、文本,或者前三者任意组合的变化。
基本用法
MutationObserver 的实例要通过调用 MutationObserver 构造函数并传入一个回调函数来创建:
observe()方法
新创建的 MutationObserver 实例不会关联 DOM 的任何部分。要把这个 observer 与 DOM 关联起来,需要使用 observe()方法。这个方法接收两个必需的参数:要观察其变化的 DOM 节点,以及一个 MutationObserverInit 对象。
MutationObserverInit 对象用于控制观察哪些方面的变化,是一个键/值对形式配置选项的字典。
例如,下面的代码会创建一个观察者(observer)并配置它观察元素上的属性变化:
observer.observe(document.body, { attributes: true });
执行以上代码后,元素上任何属性发生变化都会被这个 MutationObserver 实例发现,然后就会异步执行注册的回调函数。元素后代的修改或其他非属性修改都不会触发回调进入任务
队列。可以通过以下代码来验证:
observer.observe(document.body, { attributes: true });
document.body.className = 'foo';
console.log('Changed body class');
// Changed body class
// <body> attributes changed
注意,回调中的 console.log()是后执行的。这表明回调并非与实际的 DOM 变化同步执行。
回调与 MutationRecord每个回调都会收到一个 MutationRecord 实例的数组。MutationRecord 实例包含的信息包括发生了什么变化,以及 DOM 的哪一部分受到了影响。因为回调执行之前可能同时发生多个满足观察条件的事件,所以每次执行回调都会传入一个包含按顺序入队的 MutationRecord 实例的数组。
下面展示了反映一个属性变化的 MutationRecord 实例的数组:
(mutationRecords) => console.log(mutationRecords));
observer.observe(document.body, { attributes: true });
document.body.setAttribute('foo', 'bar');
// [
// {
// addedNodes: NodeList [],
// attributeName: "foo",
// attributeNamespace: null,
// nextSibling: null,
// oldValue: null,
// previousSibling: null
// removedNodes: NodeList [],
// target: body
// type: "attributes"
// }
// ]
下面是一次涉及命名空间的类似变化:
(mutationRecords) => console.log(mutationRecords));
observer.observe(document.body, { attributes: true });
document.body.setAttributeNS('baz', 'foo', 'bar');
// [
// {
// addedNodes: NodeList [],
// attributeName: "foo",
// attributeNamespace: "baz",
// nextSibling: null,
// oldValue: null,
// previousSibling: null
// removedNodes: NodeList [],
// target: body
// type: "attributes"
// }
// ]
连续修改会生成多个 MutationRecord 实例,下次回调执行时就会收到包含所有这些实例的数组,顺序为变化事件发生的顺序:
(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]
下表列出了 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
传给回调函数的第二个参数是观察变化的 MutationObserver 的实例,演示如下:
(mutationRecords, mutationObserver) => console.log(mutationRecords,
mutationObserver));
observer.observe(document.body, { attributes: true });
document.body.className = 'foo';
// [MutationRecord], MutationObserver