【前端基础复盘】MutationObserverInit 参数分析

【前端基础复盘】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)
})

总结

  1. 观察节点属性
    1. attributes 开启观察
    2. attributeFilter 设置白名单指定要观察的属性
    3. attributeOldValue 保留历史记录
  2. 观察节点字符数据
    1. characterData 开启观察文本节点
    2. characterDataOldValue 保留历史记录
  3. 观察节点的子节点
    1. childList 观察目标节点子节点的变化
  4. 观察子树
    1. subtree 开启观察目标节点包括子节点(深度)
相关推荐
Myli_ing1 小时前
HTML的自动定义倒计时,这个配色存一下
前端·javascript·html
dr李四维1 小时前
iOS构建版本以及Hbuilder打iOS的ipa包全流程
前端·笔记·ios·产品运营·产品经理·xcode
I_Am_Me_1 小时前
【JavaEE进阶】 JavaScript
开发语言·javascript·ecmascript
雯0609~1 小时前
网页F12:缓存的使用(设值、取值、删除)
前端·缓存
℘团子এ2 小时前
vue3中如何上传文件到腾讯云的桶(cosbrowser)
前端·javascript·腾讯云
学习前端的小z2 小时前
【前端】深入理解 JavaScript 逻辑运算符的优先级与短路求值机制
开发语言·前端·javascript
前端百草阁2 小时前
【TS简单上手,快速入门教程】————适合零基础
javascript·typescript
彭世瑜2 小时前
ts: TypeScript跳过检查/忽略类型检查
前端·javascript·typescript
FØund4042 小时前
antd form.setFieldsValue问题总结
前端·react.js·typescript·html
Backstroke fish2 小时前
Token刷新机制
前端·javascript·vue.js·typescript·vue