MutationObserver监听DOM树变化来异步的执行异步的回调

在项目中有许多的监听事件,这里介绍一个监听元素属性变化的异步回调;可运用在项目中监听某个元素的属性/个别属性变化来执行其异步的回调函数;
应用场景:该元素的属性或显示状态发生改变时,执行异步回调(如埋点或者添加属性行为);

MutationObserver使用实例

例如这个toPage()的方法,执行时实例化一个MutationObserver的构造函数,并监听该idstyle的属性;当style的属性显示时进行添加埋点;实例代码如下:

toPage(elementId, id) { // 初始化进入XX页面的埋点
    const that = this;
    const element = document.getElementById(elementId); // 对象
    console.log(element, "element")
    const observer = new MutationObserver(() => {
        // 仅在打开时触发
        if (element.style.display !== 'none') {
            console.log("打点", element)
            // that.reportEvent(id);进行页面弹窗的埋点
        }
    });
    // 述配置开始观察目标节点
    observer.observe(element, {
        attributes: true,  // configure it to listen to attribute changes,
        attributeFilter: ['style'],
    });
    // 之后,可停止观察
	//observer.disconnect();
}

MutationObserver介绍

使用MutationObserver 可以观察整个文档,DOM树的一部分或某个元素的变化;(此外还可以观察到元素的属性,子节点,文本等的变化),监听element的元素的变化,可以在dom被修改时异步的执行回调;
主要应用于:监听某个元素变化时,执行MutationObserver异步的回调;

  • MutationObserver()
    创建并返回一个新的 MutationObserver 它会在指定的DOM发生变化时被调用。
  • disconnect()
    阻止 MutationObserver 实例继续接收的通知,直到再次调用其observe()方法,该观察者对象包含的回调函数都不会再被调用。
  • observe()
    配置MutationObserver在DOM更改匹配给定选项时,通过其回调函数开始接收通知。

基本的使用

创建一个实例;通过调用MutationObserver构造函数并传入一个回调函数来创建

let observer = new MutationObserver(() => console.log('DOM was mutated!'));

这里新创建的实例不会关联任何的DOM元素,使用observe()实现监听;

  • observe使用observe(监听的dom节点, MutationObserverInit对象)
let observer = new MutationObserver(() => console.log('<body> attributes changed')); 
observer.observe(document.body, { attributes: true });
document.body.className = 'foo'; // class属性的更改,会触发observer异步的执行回调
console.log('Changed body class');
// 输出的内容; 
// Changed body class
// <body> attributes changed 异步进程
  • 回调与 MutationRecord
    每次回调都会收录到一个MutationRecord实例的数组,包含的信息发生的变化,以及DOM受到的影响;连续的改变会生成多个MutationRecord实例,回调就会返回包含所有实例的数组:[MutationRecord, MutationRecord, MutationRecord]
let observer = new MutationObserver( (mutationRecords) => console.log(mutationRecords));
observer.observe(document.body, { attributes: true });
document.body.className = 'foo';
document.body.className = 'bar';
document.body.className = 'baz';
// [MutationRecord, MutationRecord, MutationRecord]
  • disconnect();终止执行回调,实行“一刀切”的方案,会停止观察所有目标
    调用disconent()不仅会停止此后变化的回调,还会抛弃任务队列要执行的回调;
let observer = new MutationObserver(() => console.log('<body> attributes changed'));
observer.observe(document.body, { attributes: true });
document.body.className = 'foo';
observer.disconnect(); // 提前终止服务
document.body.className = 'bar';
//(没有日志输出)

MutationObserverInit的观察监听的属性值

MutationObserverInit对象的属性

  • subtree; 布尔值 - 是否观察目标节点的子树,默认为false
  • attributes; 布尔值 - 观察目标节点属性的变化; 默认false
  • attributeFilter;字符串数组 - 观察哪些属性的变化;默认观察所有属性
  • attributeOldValue; 布尔值 - 表示MutationRecord是否记录变化之前的属性值
  • characterData; 布尔值 - 表示修改字符数据是否触发变化事件;默认为 false
  • characterDataOldValue;布尔值 - 表示MutationRecord是否记录变化之前的字符数据
  • childList;布尔值 - 表示修改目标节点的子节点是否触发变化事件;默认为 false

异步回调与记录队列

  1. 记录队列;
    每次 MutationRecord 被添加到 MutationObserver 的记录队列时,仅当之前没有已排期的微
    任务回调时(队列中微任务长度为0),才会将观察者注册的回调(在初始化MutationObserver时传入)作为微任务调度到任务队列上。这样可以保证记录队列的内容不会被回调处理两次。不过在回调的微任务异步执行期间,有可能又会发生更多变化事件。因此被调用的回调会接收到一个 MutationRecord实例的数组,顺序为它们进入记录队列的顺序。回调要负责处理这个数组的每一个实例,因为函数退出之后这些实现就不存在了。回调执行后,这些 MutationRecord 就用不着了,因此记录队列会被清空,其内容会被丢弃。
  2. 调用 MutationObserver 实例的 takeRecords() 方法可以清空记录队列,取出并返回其中的所有 MutationRecord 实例。看这个例子:
let observer = new MutationObserver( (mutationRecords) => console.log(mutationRecords));
observer.observe(document.body, { attributes: true });
document.body.className = 'foo';
document.body.className = 'bar';
document.body.className = 'baz';
console.log(observer.takeRecords());
console.log(observer.takeRecords());
// [MutationRecord, MutationRecord, MutationRecord]
// []

这在希望断开与观察目标的联系,但又希望处理由于调用 disconnect() 而被抛弃的记录队列中的 MutationRecord 实例时比较有用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值