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变化后需要做的操作,回调函数以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的兼容性如下:
嗯,还算行...