【前端基础复盘】MutationObserverInit 参数分析
【前端基础复盘】MutationObserver 接口的基本使用'
在上文中,复盘了 MutationObserver 接口的基本使用,接下来继续重温一下 MutationObserver 的一些进阶特性。
MutationObserverInit 对象参数分析
MutationObserver 实例化后 需要使用 observe() 方法来关联指定的节点和配置相关的监听参数。
其中第一个必传参数是 DOM节点,第二个必传参数则是 MutationObserverInit 对象。
javascript
let observer = new MutationObserver((MutationRecord) => {
console.log(MutationRecord.map((item) => item.target))
})
let childB = document.createElement('span')
document.body.append(childA)
observer.observe(childA, { attributes: true })
在上面的代码中,创建了 MutationObserver 实例并使用 observe 方法关联 ==childA==节点,并在 MutationObserverInit 中配置监听 attributes (DOM节点属性)的变化。
那么除了 attributes 我们还可以配置什么呢?MutationObserverInit对象提供了7个配置属性,下面就来过一遍 MutationObserverInit 的配置属性。
属性 | 说明 |
---|---|
subtree | boolean,表示除了目标节点,是否观察目标节点的字数(后代)。如果是false,则只观察目标节点的变化;如果是 true,则观察目标节点及其整个子树的变化。默认为 false。 |
attributes | boolean,表示要观察目标节点的属性变化。默认 false |
attributeFilter | string[],表示要观察哪些属性的变化,默认观察所有属性 |
attributeOldValue | boolean,表示MutationRecord 是否记录变化之前的属性值,默认为 false |
characterData | boolean, 表示修改字符数据是否触发变化事件,默认false |
characterDataOldValue | boolean, 类似于attributeOldValue 表示Mutation是否记录变化之前的字符数据,默认 false |
childList | boolean,表示修改目标节点的子节点是否触发变化事件,默认为 false |
-
subtree 开启后可以观察子树
-
attributes 是一个常用的属性,一般监听节点属性(dataset、class、style等属性)变化时设置attributes为 true。
-
attributeFilter 如果监听的节点属性目标明确,就设置它,可以减少性能消耗。
-
attributeOldValue,类似于 vue中watch的oldValue,如果需要做变化对比的话,开启它。
-
监听比较大的节点时不建议开启 subtree。
-
characterData 监听 节点内容或节点文本(TextNode)的变动 示例如下
vue
<template>
<div id="container">{{ name }}</div>
</template>
<script setup>
import { ref, onMounted, nextTick } from 'vue'
let name = ref('小明')
onMounted(() => {
let observer = new MutationObserver((MutationRecord) => {
console.log('characterData change', MutationRecord)
})
observer.observe(document.querySelector('#container').firstChild, {
characterData: true,
})
setTimeout(() => {
nextTick(() => {
document.querySelector('#container').firstChild.nodeValue = 'hello world'
})
}, 1000)
})
</script>
观察属性
观察一个节点的属性,使用 attributes:true
可以像下面的写法
javascript
let observer = new MutationObserver((MutationRecord) => {
console.log('attributes change', MutationRecord)
})
observer.observe(document.body, {
attributes: true,
})
// 添加属性
document.body.setAttribute('id', '1234')
// 修改属性
document.body.setAttribute('id', '5678')
// 移除属性
document.body.removeAttribute('id')
以上变化都会被监听到
当 attributes: true
时默认观察所有的属性并且不会记录原来的值。
如果指向观察某个或某几个属性可以使用attributeFilter
来设置白名单。
如果想记录改变前的值可以将attributeOldValue
设置为true。
javascript
let observer = new MutationObserver((MutationRecords) => {
console.log('attributes change', MutationRecords)
console.log(MutationRecords.map((x) => x.oldValue)) // 打印id每次变化的值
})
observer.observe(document.body, {
attributes: true,
attributeFilter: ['id'], // 设置观察属性的白名单
attributeOldValue: true, // 记录改变前的数据
})
// 添加属性
document.body.setAttribute('id', '1234')
// 修改属性
document.body.setAttribute('id', '5678')
// 修改属性
document.body.setAttribute('id', '91011')
// 移除属性
document.body.removeAttribute('id')
document.body.setAttribute('class', 'container') // 不会被观察
观察字符数据
MutationObserver 不仅可以观察节点的 attribute 的增删改同时也可以观察文本节点(Text、Comment或ProcessingInstruction 节点)的变化。
在实际操作中使用 innerHMTL 和 innerText 观察不到,因为要使用 textContent 或者 nodeValue。
设置元素文本内容的标准方式是 textContent 属性。Element 类也定义了 innerText 属性,与 textContent 类似。
但 innerText 的定义不严谨,浏览器间的实现也存在兼容性问题,因此不建议再使用了。
vue
<template>
<div id="container">123</div>
</template>
<script setup>
import { onMounted } from 'vue'
onMounted(() => {
let dom = document.querySelector('#container')
let observer = new MutationObserver((MutationRecords) => {
console.log('characterData changed', MutationRecords)
console.log(MutationRecords.map((x) => x.oldValue)) // 打印文本每次变化的值
})
observer.observe(dom.firstChild, {
characterData: true,
subtree: true,
characterDataOldValue: true,
})
// 修改文本
dom.firstChild.textContent = 'Hello World'
// 修改文本
dom.firstChild.textContent = 'Hello World2'
// 修改文本
dom.firstChild.textContent = 'Hello World3'
// 修改文本
dom.firstChild.textContent = '666'
})
</script>
观察子节点
MutationObserver 同时可以观察目标节点的子节点的添加和移除。
javascript
onMounted(() => {
let dom = document.querySelector('#container')
let observer = new MutationObserver((MutationRecords) => {
console.log('childList changed', MutationRecords)
})
observer.observe(dom, {
childList: true,
})
// 添加属性
const domH1 = document.createElement('h1')
const domH2 = document.createElement('h2')
const domH3 = document.createElement('h3')
dom.append(domH1)
dom.append(domH2)
dom.append(domH3)
dom.removeChild(domH3)
})
总结
- 观察节点属性
- attributes 开启观察
- attributeFilter 设置白名单指定要观察的属性
- attributeOldValue 保留历史记录
- 观察节点字符数据
- characterData 开启观察文本节点
- characterDataOldValue 保留历史记录
- 观察节点的子节点
- childList 观察目标节点子节点的变化
- 观察子树
- subtree 开启观察目标节点包括子节点(深度)