MutationObserver DOM变化的观察

简单的给MutationObserver做个测试及总结笔记。

MutationObserver,window上的一个(构造)函数,可以通过其创建的观察者(观察对象)达到观察DOM的变化的效果。

可适用的需求:开发者在DOM变化过程中的debug、根据页面变化处理不同的资源、拦截网页是否被注入动态内容加载的脚本等等...

简单的案例代码如下,比如观察属性变化:

<button id="J_click">click</button>
<div id="J_dom" data-num="1">hello</div>
<script>
    var dom = document.getElementById('J_dom');

    var domObservable = new MutationObserver(function (mutationRecord) {
        console.log('mutationRecord : ', mutationRecord)
    });

    document.getElementById('J_click').addEventListener('click', domChange, !1);
    
    domObservable.observe(dom, {
        attributes: true,
        attributeOldValue: true
    })

    function domChange() {
        dom.setAttribute('data-num', +(dom.getAttribute('data-num')) + 1);
    }
</script>

点击"click"按钮,J_dom的data-num属性从0变为1。控制台输出如下MutationRecord对象列表:

MutationObserver DOM变化的观察

 

MutationObserver 构造函数需要传入一个回调函数用以执行观察到DOM变化后需要做的操作,回调函数以MutationRecord对象列表作为参数。

MutationRecord对象列表

MutationRecord对象包含以下属性:

1. type,DOM变化的类型,DOM属性变化为"attributes";DOM内数据变化为"characterData";子节点树结构变化为"childList";

2. target,如果如果type不为"childList",则代表发生变化的节点;如果type为"childList",则是被操作子节点(新增或删除)的父节点;

3. addedNodes,被观察的DOM内新增的节点列表;

4. removedNodes,被观察的DOM内移除的节点列表;

5. previousSibling,被添加或移除节点之前的兄弟节点;

6. nextSibling,被添加或移除节点之后的兄弟节点;

7. attributeName,被修改属性的属性名;

8. attributeNamespace,被修改属性的命名空间;

9. oldValue,旧值,根据type而返回对应的旧属性或旧数据。

观察者(观察对象)

观察者对象上存在3个操作方法:observe、takeRecords、disconnect。

observe方法指定一个被观察的DOM,配置该节点内的哪些变化需要被观察。方法使用如下: 

var domObservable = new MutationObserver(function (mutationRecord) {
    // 变化后的处理代码
});

domObservable.observe(/* 被观察的DOM */, /* 配置参数 */{
    subtree: false,  // 观察范围是否包含子节点的变化,true则包括,false则不包括
    childList: false,  // 被观察的节点的子节点变化,true则观察,false则不观察
    attributes: false,  // 被观察的节点的属性变化,true则观察,false则不观察
    attributeOldValue: false,  // MutationRecord对象上是否返回被观察的节点的属性变化之前的旧值,true则返回,false则不返回
    attributeFilter: [/* 指定被观察的属性列表 */],  // attributes为true时生效,比如设置了列表为['class'],则只观察class的变化
    characterData: false,   // 被观察的节点的数据变化,true则观察,false则不观察
    characterDataOldValue: false  // MutationRecord对象上是否返回被观察的节点的数据变化之前的旧值,true则返回,false则不返回
});
/**
  * 注意:
  * 在attributes未被配置的情况下,如果attributeOldValue为true或者attributeFilter被设置,则attributes默认为true。
  * 在characterData未被配置的情况下,如果characterDataOldValue为true,则characterData默认为true。
  */

takeRecords方法返回当前操作后的MutationRecord对象列表。方法使用如下:

<button id="J_takeRecords">take records</button>
<div id="J_dom" data-num="1">
    <span id="J_words">0</span>
    <div id="J_subDom"></div>
</div>
<script>
    var value = 0;
    var operateDom = document.getElementById('J_dom');
    var wordsDom = document.getElementById('J_words');
    var takeRecordsBtn = document.getElementById('J_takeRecords');

    takeRecordsBtn.addEventListener('click', takeRecords, !1);

    function takeRecords() {
        console.log('%c both change attribute and subtree', 'color:blue');
        operateDom.setAttribute('data-num', +(operateDom.getAttribute('data-num')) + 1);
        wordsDom.innerText = wordsDom.innerText === '0' ? '' : '0';
        var result = domObservable.takeRecords();
        console.log(result);
    }

    var domObservable = new MutationObserver(function (mutationsList) {
        console.log('mutationsList ', mutationsList);
    })

    domObservable.observe(operateDom, {
        subtree: true,
        attributes: true,
        attributeOldValue: true,
        characterData: true,
        characterDataOldValue: true
    });
</script>
<!-- 点击"take records"按钮,J_dom的data-num属性从0变为1,J_words里的0变成零 -->
<!-- 分别为一次attrbutes和一次characterData变化,takeRecords方法被调用返回一个包含两次变化的MutationRecord对象列表。
-->

disconnect方法移除该观察者上的所有观察并清空该对象的MutationRecord对象列表。

最后,MutationObserver的兼容性如下:

MutationObserver DOM变化的观察

嗯,还算行...

 

上一篇:Notification 浏览器的消息推送


下一篇:《TCP IP 详解卷1:协议》阅读笔记 - 第五章