👓 MutationObserver
📗 概述
MutationObserver
是DOM3 Events规范中的一部分,它提供了监视DOM树变化并及时作出响应的能力。通过使用MutationObserver,开发人员可以监听DOM节点的变化,并执行自定义的回调函数。
🔬 工作模型
每个MutationObserver实例都有一个与之对应的通知队列,当实例观察的目标DOM节点发生变化时,回调函数并不会同步执行,而是会将目标节点的变化包装成一个对象放入通知队列。
需注意的是,一个MutationObserver实例也对应一个回调函数(开发者自定义),且其是一个微任务,它会在本轮次事件循环中目标节点第一次变化时被放入微队列,并在下轮事件循环中被执行。
回调函数执行时,MutationObserver实例对应的队列会作为该回调函数的实参传入,且队列会转化成JS中的数组类型。
tip: MutationObserver实例观察的是DOM树,是语言层面上的变化,可以理解为JS中DOM对象的变化,而不是浏览器渲染图形层面上的变化。
🏃♂️ 创建实例
一个MutationObserver实例负责监听一个DOM节点的变化,实例化时需要传入一个类型为MutationCallback
的参数,这个参数便是实例监听执行的回调函数。有关MutationCallBack回调函数的具体内容,以下会单独讲述。
🧭 实例API
observe
observe方法需传入一个目标节点和一个观察配置。在调用该方法后,实例将会开始观察目标节点。这意味着,实例开始接收节点变化通知。若节点发生变化,则回调函数便会被执行,这个过程会受到类型为MutationObserverInit
的观察配置的影响。有关观察配置的具体内容,以下也会单独讲述。
disconnect
调用实例的disconnect方法后,其会停止接收更改通知。这意味着,它将停止观察目标节点的任何更改,即使目标节点发生了任何变化,回调也不会被执行,直到再次调用其observer方法。
takeRecords
调用实例的takeRecords方法后,其对应的通知队列中的所有待处理通知都会被删除,并将它们返回至一个新的数组对象中。
⏰ 回调函数
目标节点发生变化,则在下一轮事件循环中,回调函数便会被执行。回调执行时,会传入两个参数。第一个参数是DOM变化对象数组,有关DOM变化对象的具体内容会在下面进行讲述。第二个参数是当前MutationObserver实例。
tip: mutations数组中只存储了上一轮事件循环中目标节点发生的变化。
🌱 变化对象
每个 MutationRecord
变化对象都代表一个独立的 DOM 变化,其有以下常用属性。
属性名 | 类型 | 描述 |
---|---|---|
type | string | 若为属性节点变化,则值为attributes; 若为文本节点和注释节点字符变化,则值为characterData; 若为添加或删除子节点,则值为childList |
target | Node | 发生变化的节点 |
addedNodes | NodeList | 返回被添加的节点,若没有节点被添加,则值为空的NodeList |
removedNodes | NodeList | 返回被删除的节点,若没有节点被删除,则值为空的NodeList |
attributeName | string | 返回被修改的属性的属性名,或者为 null |
attributeNamespace | string | 返回被修改的属性的命名空间,或者为 null |
oldValue | string | 若为属性attributes变化,则返回变化之前的属性; 若为characterData变化,则返回变化之前的数据; 若为子节点树childList变化,则返回null |
📢 监听配置
MutationObserverInit
实例用于配置MutationObserver实例监听的初始化对象,它定义了要观察的 DOM 变化类型和其他选项。MutationObserverInit有以下可配置的属性。
属性名 | 默认值 | 描述 |
---|---|---|
attributes | false | 当为true时,将会监听目标节点属性值的变化 |
characterData | false | 当为true时,将会监听文本节点或注释节点上的字符变化 |
childList | false | 当为true时,将会监听目标节点的子节点添加和删除 |
attributeFilter | / | 用于声明哪些属性名会被监听的数组。若不声明,则全部监听 |
attributeOldValue | false | 当为true时,记录目标节点属性变化前的旧值 |
characterDataOldValue | false | 当为true时,记录目标节点文本变化前的旧值 |
subtree | false | 当为true时,目标节点范围扩大至以参数target节点为根节点的子树中的所有节点 |
tip:
- 调用MutationObserver实例的observe()方法时,需配置MutationObserverInit实例的
attributeOldValue
属性或characterDataOldValue
属性为true,后续MutationRecord实例的oldValue
属性才会有值。- ⭐️⭐️⭐️
characterData
为true时,使用targetElement.innerText='FatGod'
这种方式修改文本值并不能被成功监听,因为这种方式的本质是将元素的原文本节点删除,插入新的文本节点,所以该过程能够监听到目标节点的childList
类型变化。characterData
类型的变化监听只适用于节点类型为文本或者注释的节点。若需更改文本节点或注释节点的字符可以使用characterDataNode.nodeValue = 'FatGod'
该种方式,nodeValue
是Node
接口中的属性。