MutationObserver 介绍

MutationObserver 是是一个用于监视 DOM 变动的 Web API。通过它可以监控 DOM 树中的更改,比如元素的属性、子元素的增加和删除等,并在这些变化发生时执行回调函数。可以替代过时的 Mutation Events,它具有更高的性能和更广的适用性。

使用步骤详细说明

1. 创建观察者实例

MutationObserver 构造函数接收一个回调函数,当观察到 DOM 变化时,这个回调函数会被调用。

const observer = new MutationObserver((mutationsList, observer) => {
    // 遍历所有的 MutationRecord 对象
    mutationsList.forEach(mutation => {
        switch(mutation.type) {
            case 'childList':
                console.log('A child node has been added or removed.');
                console.log('Added nodes:', mutation.addedNodes);
                console.log('Removed nodes:', mutation.removedNodes);
                break;
            case 'attributes':
                console.log(`The ${mutation.attributeName} attribute was modified.`);
                break;
            case 'characterData':
                console.log('The character data has changed.');
                break;
        }
    });
});
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
2. 定义观察选项

observe 方法的第二个参数是一个配置对象,用于指定观察的类型和范围。

const config = { 
    attributes: true,           // 监视属性的变化
    childList: true,            // 监视子节点的变化
    subtree: true,              // 监视整个子树
    characterData: true,        // 监视节点内容或文本的变化
    attributeOldValue: true,    // 记录属性变化前的值
    characterDataOldValue: true // 记录文本内容变化前的值
};
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
3. 选择要观察的目标节点

目标节点是希望监视其变动的 DOM 元素。

const targetNode = document.getElementById('someElementId');
  • 1.
4. 开始观察目标节点

调用 observe 方法开始观察目标节点。

observer.observe(targetNode, config);
  • 1.
5. 停止观察

当不再需要观察时,可以调用 disconnect 方法停止观察。

observer.disconnect();
  • 1.

MutationRecord 对象详解

每个 MutationRecord 对象表示一个检测到的变化。其属性如下:

  • type: 变化的类型,可以是 "attributes"、"characterData" 或 "childList"。
  • target: 变化所影响的目标节点。
  • addedNodes: 一个包含所有新添加的子节点的 NodeList
  • removedNodes: 一个包含所有被移除的子节点的 NodeList
  • previousSibling: 被添加或移除节点的前一个兄弟节点。
  • nextSibling: 被添加或移除节点的下一个兄弟节点。
  • attributeName: 变化的属性的名称。
  • attributeNamespace: 变化的属性的命名空间。
  • oldValue: 属性或字符数据的先前值(如果配置中指定了 attributeOldValuecharacterDataOldValue)。

实用场景及高级技巧

1. 动态内容加载

可以用于监控动态加载内容的变化。例如,监视 AJAX 请求插入的内容。

observer.observe(document.body, { childList: true, subtree: true });
  • 1.
2. 表单自动保存

监控表单元素的变化并自动保存用户输入的数据。

const formObserver = new MutationObserver((mutationsList, observer) => {
    // 保存表单数据逻辑
});
formObserver.observe(document.querySelector('form'), { attributes: true, childList: true, subtree: true });
  • 1.
  • 2.
  • 3.
  • 4.
3. 动态调整页面布局

根据 DOM 的变化动态调整页面布局或内容。

const layoutObserver = new MutationObserver((mutationsList, observer) => {
    // 动态调整布局逻辑
});
layoutObserver.observe(document.getElementById('dynamicContent'), { childList: true, subtree: true });
  • 1.
  • 2.
  • 3.
  • 4.

性能考虑

尽管 MutationObserver 性能优于 Mutation Events,但在处理大量变动时仍需谨慎。避免过多的 DOM 操作和复杂的回调函数逻辑,可以使用 debouncethrottle 技术优化性能。

示例代码:动态加载内容监视

const contentObserver = new MutationObserver((mutationsList, observer) => {
    mutationsList.forEach(mutation => {
        if (mutation.type === 'childList') {
            mutation.addedNodes.forEach(node => {
                if (node.nodeType === 1) { // 确保是元素节点
                    console.log('New element added:', node);
                    // 这里可以添加处理新加载内容的逻辑
                }
            });
        }
    });
});

const config = { childList: true, subtree: true };
contentObserver.observe(document.body, config);
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

通过这些详细的步骤和示例代码,可以更深入地理解和应用 MutationObserver,从而实现对 DOM 变化的高效监控和处理。

参考文章

 JS MutationObserver(JS变动观察器)