MutationObserver 是 JavaScript 中用于监听 DOM 变化的强大 API,能够高效地监测节点添加/删除、属性修改、文本内容变更等操作,适用于动态内容加载、表单验证、响应式布局等场景。以下是其完整用法指南:
一、核心概念
- 异步触发:所有 DOM 变化会先被记录,待其他脚本执行完成后统一触发回调,避免频繁操作导致的性能问题。
- 弱引用机制:观察器对节点的引用为弱引用,节点被移除且不可访问时会被垃圾回收,不影响内存管理。
- 配置优化 :通过
config对象指定监听类型,避免不必要的回调调用以节省资源。
二、基本用法
1. 创建观察器实例
javascript
const observer = new MutationObserver((mutationsList, observer) => {
mutationsList.forEach(mutation => {
console.log('变化类型:', mutation.type);
// 处理具体变化(如新增节点、属性修改等)
});
});
- 参数 :回调函数接收两个参数:
mutationsList:包含所有 DOM 变化的MutationRecord对象数组。observer:观察器实例本身,可用于停止观察。
2. 配置观察选项
通过 config 对象指定监听类型,常用配置项如下:
| 配置项 | 说明 |
|---|---|
childList |
监听子节点的添加或删除(true/false)。 |
attributes |
监听属性变化(true/false)。 |
attributeFilter |
指定监听的属性名数组(如 ['class', 'id']),不指定则监听所有属性。 |
attributeOldValue |
记录属性旧值(需 attributes: true)。 |
characterData |
监听文本节点内容变化(true/false)。 |
characterDataOldValue |
记录文本旧值(需 characterData: true)。 |
subtree |
监听所有后代节点的变化(true/false)。 |
示例:
javascript
const config = {
childList: true, // 监听子节点变化
attributes: true, // 监听属性变化
subtree: true, // 监听所有后代节点
attributeFilter: ['class', 'id'] // 仅监听 class 和 id 属性
};
3. 启动观察
javascript
const targetNode = document.getElementById('target');
observer.observe(targetNode, config);
- 参数 :
targetNode:要监听的 DOM 节点。config:观察选项对象。
4. 停止观察
-
停止所有监听 :
javascriptobserver.disconnect(); -
获取未处理的变化记录 (同步执行):
javascriptconst records = observer.takeRecords(); console.log(records); // 返回未处理的 MutationRecord 数组
三、高级技巧
1. 动态内容加载
监听 AJAX 插入的内容或动态加载的组件:
javascript
const contentObserver = new MutationObserver((mutationsList) => {
mutationsList.forEach(mutation => {
if (mutation.type === 'childList') {
mutation.addedNodes.forEach(node => {
if (node.nodeType === 1) { // 元素节点
console.log('新增元素:', node);
// 处理新加载内容的逻辑
}
});
}
});
});
const config = { childList: true, subtree: true };
contentObserver.observe(document.body, config);
2. 表单验证
监听表单元素属性变化(如 disabled、value
javascript
const formObserver = new MutationObserver((mutationsList) => {
mutationsList.forEach(mutation => {
if (mutation.type === 'attributes' && mutation.attributeName === 'value') {
console.log('表单值变化:', mutation.target.value);
// 执行验证逻辑
}
});
});
const input = document.getElementById('username');
formObserver.observe(input, { attributes: true, attributeOldValue: true });
3. 响应式布局
根据 DOM 变化动态调整布局:
javascript
const layoutObserver = new MutationObserver(() => {
adjustLayout(); // 自定义布局调整函数
});
const container = document.getElementById('container');
layoutObserver.observe(container, { childList: true, subtree: true });
4. 自定义组件开发
监听组件内部 DOM 变化并更新状态:
javascript
class CustomComponent {
constructor(element) {
this.element = element;
this.observer = new MutationObserver((mutationsList) => {
mutationsList.forEach(mutation => {
if (mutation.type === 'childList') {
this.updateState(); // 自定义状态更新函数
}
});
});
this.observer.observe(this.element, { childList: true, subtree: true });
}
updateState() {
console.log('组件状态更新');
}
}
四、注意事项
- 性能优化 :
- 避免过度监听(如不必要的
subtree: true)。 - 使用
attributeFilter缩小监听范围。
- 避免过度监听(如不必要的
- 文本节点监听限制 :
- 输入中文字符时可能无法触发
characterData变化。 - 文本节点被完全删除后,新输入的文本会生成新节点,需通过
childList监听父容器。
- 输入中文字符时可能无法触发
- 与
IntersectionObserver的区别 :MutationObserver监听 DOM 变化,IntersectionObserver监听元素可见性变化。MutationObserver需手动停止监听(disconnect()),IntersectionObserver可通过unobserve()停止指定元素监听。
五、示例汇总
示例 1:监听元素属性变化
javascript
const box = document.getElementById('box');
const observer = new MutationObserver((mutations) => {
mutations.forEach(mutation => {
if (mutation.type === 'attributes') {
console.log('属性变化:', mutation.attributeName, '旧值:', mutation.oldValue);
}
});
});
const config = {
attributes: true,
attributeOldValue: true,
attributeFilter: ['class', 'style']
};
observer.observe(box, config);
示例 2:监听子元素添加/删除
javascript
const list = document.getElementById('list');
const observer = new MutationObserver((mutations) => {
mutations.forEach(mutation => {
if (mutation.type === 'childList') {
mutation.addedNodes.forEach(node => {
if (node.nodeType === 1) console.log('新增子元素:', node);
});
mutation.removedNodes.forEach(node => {
if (node.nodeType === 1) console.log('移除子元素:', node);
});
}
});
});
observer.observe(list, { childList: true, subtree: true });
示例 3:监听文本内容变化
javascript
const editableDiv = document.getElementById('editable');
const observer = new MutationObserver((mutations) => {
mutations.forEach(mutation => {
if (mutation.type === 'characterData') {
console.log('文本变化:', mutation.target.nodeValue);
}
});
});
observer.observe(editableDiv, { characterData: true, subtree: true });
六、总结
MutationObserver 是监测 DOM 变化的理想工具,通过合理配置可实现动态内容加载、表单验证、响应式布局等功能。使用时需注意性能优化,避免过度监听,并根据实际需求选择合适的监听类型。结合具体场景,MutationObserver 能显著提升网页的交互性和动态响应能力。