【前端基础复盘】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 开启观察目标节点包括子节点(深度)
相关推荐
蜗牛快跑21310 分钟前
面向对象编程 vs 函数式编程
前端·函数式编程·面向对象编程
Dread_lxy11 分钟前
vue 依赖注入(Provide、Inject )和混入(mixins)
前端·javascript·vue.js
涔溪1 小时前
Ecmascript(ES)标准
前端·elasticsearch·ecmascript
榴莲千丞1 小时前
第8章利用CSS制作导航菜单
前端·css
奔跑草-1 小时前
【前端】深入浅出 - TypeScript 的详细讲解
前端·javascript·react.js·typescript
羡与1 小时前
echarts-gl 3D柱状图配置
前端·javascript·echarts
guokanglun1 小时前
CSS样式实现3D效果
前端·css·3d
咔咔库奇1 小时前
ES6进阶知识一
前端·ecmascript·es6
前端郭德纲2 小时前
浏览器是加载ES6模块的?
javascript·算法
JerryXZR2 小时前
JavaScript核心编程 - 原型链 作用域 与 执行上下文
开发语言·javascript·原型模式