【前端基础复盘】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 开启观察目标节点包括子节点(深度)
相关推荐
ChangYan.38 分钟前
直接下载源码但是执行npm run compile后报错
前端·npm·node.js
skywalk81631 小时前
在 FreeBSD 上可以使用的虚拟主机(Web‑Hosting)面板
前端·主机·webmin
ohyeah2 小时前
深入理解 React 中的 useRef:不只是获取 DOM 元素
前端·react.js
MoXinXueWEB2 小时前
前端页面获取不到url上参数值
前端
低保和光头哪个先来2 小时前
场景6:对浏览器内核的理解
开发语言·前端·javascript·vue.js·前端框架
想要一只奶牛猫2 小时前
Spring Web MVC(三)
前端·spring·mvc
奋飛2 小时前
微前端系列:核心概念、价值与应用场景
前端·微前端·micro·mfe·什么是微前端
ji_shuke3 小时前
canvas绘制拖拽箭头
开发语言·javascript·ecmascript
2501_946244783 小时前
Flutter & OpenHarmony OA系统设置页面组件开发指南
开发语言·javascript·flutter
cz追天之路3 小时前
华为机考 ------ 识别有效的IP地址和掩码并进行分类统计
javascript·华为·typescript·node.js·ecmascript·less·css3