Skip to main content

MutationObserver 监听位置

什么是 MutationObserver

MutationObserver 用于监听 DOM 树的修改,可用于监听元素位置的变化。

一、基本用法

MutationObserver 是个构造函数。需要使用 new 关键字调用,通过 observe 方法指定监听的元素。

mutationObserver.observe(target, options)
  • target: 监听的元素
  • options: 监听的范围(必须有 childListattributescharacterData 中一种或多种)
    • childList(boolean),表示是否监听子节点的变动;
    • attributes(boolean),表示是否监属性的变动;
    • characterData(boolean),表示是否监听节点内容/文本的变动;
    • subtree(boolean),表示是否监听所有后代节点;
    • attributeFilter(array),表示观察特定属性;
    • attributeOldValue(boolean),表示观察 attributes 变动时,是否需要记录变动前的属性值;
    • characterDataOldValue(boolean),表示观察 characterData 变动,是否需要记录变动前的值;
注意

MutationObserveroptions 是必选项,而 ResizeObserver 是可选。

const mutationObserver = new MutationObserver(entries => {
console.log(entries)
});
const options = {
childList: true, // 子节点的变动(新增、删除或者更改)
attributes: true, // 属性的变动
characterData: true, // 节点内容或节点文本的变动
subtree: true, // 是否将观察器应用于该节点的所有后代节点
attributeFilter: ['class', 'style'], // 观察特定属性
attributeOldValue: true, // 观察 attributes 变动时,是否需要记录变动前的属性值
characterDataOldValue: true // 观察 characterData 变动,是否需要记录变动前的值
}
mutationObserver.observe(document.querySelector('#box'), options)

当该 DOM 元素节点增减、属性/宽高/内容的变化时输出:

其中,几个比较关键的属性如下:

  • attributeName: 表示修改的属性名称;
  • target: 修改的目标;
  • type: 类型。

二、获取监听记录

在终止 MutationObserver 之前,可通过 takeRecords 获取已有的 mutationRecords 记录:

const mutationObserver = new MutationObserver((mutation) => console.log(mutation))
mutationObserver.observe(document.body, {
attributes: true
})

document.body.className = 'main'
document.body.className = 'container'
document.body.className = 'box'

// 获取修改记录
const mutationRecords = mutationObserver.takeRecords()
console.log(mutationRecords) // [MutationRecord, MutationRecord, MutationRecord]

三、取消监听

removeEventListener 同理,需要取消监听。

可通过 disconnect 取消 mutationObserver 监听。

const mutationObserver = new MutationObserver(entries => {
console.log(entries)
});
mutationObserver.observe(document.querySelector('#box'), {
attributes: true
})
mutationObserver.observe(document.body, {
attributes: true
})

// 2s 后取消所有节点的监听
setTimeout(() => {
mutationObserver.disconnect()
}, 2000)

在 React 中使用时,一般会在 useEffect 的返回值中对 MutationObserver 统一销毁:

useEffect(() => {
const mutationObserver = new MutationObserver(entries => {
console.log(entries)
});
mutationObserver.observe((triggerNode.current as any), {
attributes: true,
childList: false,
subtree: false
})
return () => mutationObserver.disconnect()
}, [])