JavaScript MutationObserver用法( 监听DOM变化 )

在Vue的开发中,

Vue2 中会用侦听器watch来监听数据的变化。

Vue3 中使用 proxy 替代了defineProperty用来监听整个对象 ,性能大大提高。

那如果想监听DOM的变化呢,该怎么做呢?

JavaScript 提供了多种 API 来操作 DOM 结构。而在操作 DOM 时,经常需要监测 DOM 的变化,此时,MutationObserver 就显得非常有用。

一、MutationObserver 简介

MutationObserver 是 HTML5 引入的一种用于监听 DOM 树变化的接口。它可以在 DOM 树发生以下变化时执行回调函数:

  • 元素的子树发生变化(子节点的添加、删除或重排序)。
  • 元素的属性发生变化。
  • 元素的文本内容发生变化。

与传统的 DOM 事件(如 DOMSubtreeModified、DOMNodeInserted、DOMNodeRemoved 等)相比,MutationObserver 提供了更高效和更灵活的 API。

原理:

MutationObserver 通过异步方式监测 DOM 变化,这意味着当 DOM 变化发生时,MutationObserver 不会立即执行回调函数,而是将这些变化存入一个队列中,并在本轮 JavaScript 执行完之后,才批量处理这些变化。这种异步批量处理的机制,使得 MutationObserver 更加高效。

二、MutationObserver 基础用法

创建一个 MutationObserver 实例,传入一个回调函数。

使用 observe 方法开始监听目标节点及其相关的变化。

当不再需要监听时,使用 disconnect 方法停止观察。停止MutationObserver对象的观察,且清空所有的MutationRecord对象。

observe 配置项:

接受两个参数:目标节点和一个配置对象。配置对象用于指定要观察哪些类型的变化。常用配置项包括:

|-----------------------|--------------------------------------------|-------|
| 属性 | 说明 | 默认值 |
| subtree | 当设置为 true 时,监视目标节点及其所有后代节点的变化 | false |
| childList | 当目标节点(如果 subtree 为 true,则包含子孙节点)添加或删除时触发回调 | false |
| attributes | 当元素的属性变化时触发回调 | false |
| attributeFilter | 要监视的特定属性名称的数组。如果未包含此属性,则对所有属性的更改都会触发变动通知 | 无默认值 |
| characterData | 设为 true 以监视指定目标节点或子节点树中节点所包含的字符数据的变化 | false |
| attributeOldValue | 当属性变化时,记录变化前的属性值 | false |
| characterDataOldValue | 当文本节点变化时,记录变化前的文本内容 | false |

代码实现:

复制代码
// 1. 创建一个 MutationObserver 实例,并传入回调函数
const observer = new MutationObserver((mutationsList, observer) => {
  mutationsList.forEach(mutation => {
	// 处理逻辑
    if (mutation.type === 'childList') {
      console.log('已添加或删除子节点。');
    } else if (mutation.type === 'attributes') {
      console.log('修改了 ' + mutation.attributeName + ' 属性');
    }
  }
});

// 2. 开始监听目标节点
const elementNode = document.querySelector('#myDiv');
const config = { attributes: true, childList: true, subtree: true };

observer.observe(elementNode, config);

// 3. 停止监听
// observer.disconnect();
三、MutationObserver 使用场景
1:监控动态内容加载

页面数据通过axios接口请求动态加载到页面上的。可以使用 MutationObserver 监控动态内容的加载,在加载完成后进行一些操作(如:绑定事件、修改样式等)

复制代码
// 动态内容加载容器
const contentEle = document.querySelector('.content');

// 创建观察者实例
const observer = new MutationObserver((mutationsList) => {
  for (let mutation of mutationsList) {
    if (mutation.type === 'childList') {
      console.log('New content has been loaded:', mutation.addedNodes);
      // 对新增的节点进行一些操作
      mutation.addedNodes.forEach(node => {
        if (node.nodeType === Node.ELEMENT_NODE) {
          // 绑定事件,或执行其他逻辑
          node.addEventListener('click', () => console.log('New element clicked!'));
        }
      });
    }
  }
});

// 配置选项
const config = { childList: true, subtree: true };

// 开始监控
observer.observe(contentEle, config);
2:监控属性变化

假如需要页面的某个元素 data-v-status 属性发生变化时做出响应处理。MutationObserver 可以轻松实现这一需求。

复制代码
// 目标节点
const statusEle = document.querySelector('#status');

// 创建观察者实例
const observer = new MutationObserver((mutationsList) => {
  for (let mutation of mutationsList) {
    if (mutation.type === 'attributes' && mutation.attributeName === 'data-v-status') {
      console.log('Status changed to:', statusEle.getAttribute('data-v-status'));
    }
  }
});

// 配置选项
const config = { attributes: true, attributeFilter: ['data-v-status'] };

// 开始监控
observer.observe(statusEle, config);
3:批量修改 DOM, 优化页面性能

批量向Dom节点中添加了 N多个子节点, MutationObserver 会统一处理这些 DOM 变化,有效减少了重绘和重排操作,优化页面性能。

复制代码
// 目标节点
const containerEle = document.querySelector('#container');

// 创建观察者实例
const observer = new MutationObserver((mutationsList) => {
  mutationsList.forEach(mutation => {
    if (mutation.type === 'childList') {
      // 批量处理逻辑
      console.log('批量处理DOM更改');
    }
  });
});

// 配置选项
const config = { childList: true, subtree: true };

// 开始监控
observer.observe(containerEle, config);

// 批量修改 DOM
const fragment = document.createDocumentFragment();
for (let i = 0; i < 500; i++) {
  const newDiv = document.createElement('div');
  newDiv.textContent = `Item ${i}`;
  fragment.appendChild(newDiv);
}
containerEle.appendChild(fragment);
4:删除恶意Javascript脚本, 防止 DOM 劫持

在一些恶意脚本或第三方插件注入的情况下,DOM 结构可能会被劫持。可以使用 MutationObserver 检测 DOM 结构的异常变化,从而做出防护措施处理。

复制代码
 // 目标节点
const body = document.body;

// 创建观察者实例
const observer = new MutationObserver((mutationsList) => {
  for (let mutation of mutationsList) {
    if (mutation.type === 'childList') {
      mutation.addedNodes.forEach(node => {
        if (node.nodeType === Node.ELEMENT_NODE && node.tagName === 'SCRIPT') {
          console.warn('检测到潜在的恶意脚本!');
          // 移除恶意脚本
          node.parentNode.removeChild(node);
        }
      });
    }
  }
});

// 配置选项
const config = { childList: true, subtree: true };

// 开始监控
observer.observe(body, config);
四、结语

MutationObserver 是一个非常强大的 API,额外提供了一种高效、灵活的方式来监听和响应 DOM 变化。相比较于传统 DOM 事件监听器的诸多局限性,它通过异步、批量的方式处理 DOM 变化,极大的提高了性能和效率。在实际开发中,合理使用 MutationObserver 可以帮助我们更好地控制 DOM 操作,提高代码的健壮性和可维护性。

相关推荐
酷柚易汛2 小时前
酷柚易汛ERP 2025-12-26系统升级日志
java·前端·数据库·php
Onlyᝰ2 小时前
前端调用接口进行上传文件
前端
90后的晨仔2 小时前
2025,我的“AI搭子”:那个我以为用不上的AI,成了我每天都离不开的搭档!!
前端
hashiqimiya2 小时前
JavaScript的object的使用和监控打印日志
前端·javascript·vue.js
颜酱2 小时前
从0到1实现通用微任务调度器:理解前端异步调度核心
前端
Bruce_Liuxiaowei2 小时前
Nmap+Fofa 一体化信息搜集工具打造
运维·开发语言·网络·网络安全
智航GIS2 小时前
5.1 if语句基础
开发语言·python
bu_shuo2 小时前
MATLAB中的转置操作及其必要性
开发语言·算法·matlab
梦6503 小时前
Vue 组件 vs React 组件深度对比
javascript·vue.js·react.js