【前端基础复盘】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 开启观察目标节点包括子节点(深度)
相关推荐
Jonathan Star5 小时前
沉浸式雨天海岸:用A-Frame打造WebXR互动场景
前端·javascript
工业甲酰苯胺5 小时前
实现 json path 来评估函数式解析器的损耗
java·前端·json
老前端的功夫5 小时前
Web应用的永生之术:PWA落地与实践深度指南
java·开发语言·前端·javascript·css·node.js
LilySesy6 小时前
ABAP+WHERE字段长度不一致报错解决
java·前端·javascript·bug·sap·abap·alv
Wang's Blog7 小时前
前端FAQ: Vue 3 与 Vue 2 相⽐有哪些重要的改进?
前端·javascript·vue.js
再希7 小时前
React+Tailwind CSS+Shadcn UI
前端·react.js·ui
用户47949283569157 小时前
JavaScript 的 NaN !== NaN 之谜:从 CPU 指令到 IEEE 754 标准的完整解密
前端·javascript
群联云防护小杜7 小时前
国产化环境下 Web 应用如何满足等保 2.0?从 Nginx 配置到 AI 防护实战
运维·前端·nginx
醉方休8 小时前
Web3.js 全面解析
前端·javascript·electron
前端开发爱好者8 小时前
前端新玩具:Vike 发布!
前端·javascript