浏览器的5种观察器

IntersectionObserver 交叉观察器

该观察器自动"观察"目标元素与根元素交叉区域的变化。默认根元素为文档视口,此时交叉区域的变化决定了用户在当前视口能否看到目标元素,因此它经常被用于“元素可见性”观察。比如:图片懒加载、无限滚动、广告曝光量统计等。

兼容性:IE不支持

基本用法

1. 创建观察器实例

let options = { //配置observer实例的对象
    // root: document.querySelector('#parentBox'), // 指定根元素,必须是目标元素的父级或祖先元素; 默认:文档视口
    // rootMargin: "0px 0px 0px 0px", //根元素的外边距。类似于 CSS 中的 margin 属性。默认值是"0px 0px 0px 0px",分别表示 top、right、bottom 和 left 四个方向的值,用来扩展或缩小rootBounds这个矩形的大小,从而影响intersectionRect交叉区域的大小。
    threshold: [0] //目标元素和根元素相交部分的比例达到该值的时候,callback 函数将会被执行,eg: 1 、[0.5 , 1],当为数组时每达到该值都会执行 callback 函数。默认值为[0]。
}
let observer = new IntersectionObserver(callback[, options]);

2. 定义观察到目标元素与根元素交叉区域变化时的回调函数 callback(entries, observer)。entries数组中,每个成员都是一个IntersectionObserverEntry对象,如果同时有两个被观察的对象的可见性发生变化,entries数组就会有两个成员。一般会触发两次callback。一次是目标元素刚刚进入视口(开始可见),另一次是完全离开视口(开始不可见)。

let callback = (entries, observer) => { 
    entries.forEach(entry => {
        consloe.log(entry) //包含目标元素的信息的对象
        // entry.time:可见性发生变化的时间,是一个高精度时间戳,单位为毫秒
        // entry.target:被观察的目标元素,是一个 DOM 节点对象
        // entry.rootBounds:根元素的矩形区域的信息,getBoundingClientRect()方法的返回值,如果没有根元素(即直接相对于视口滚动),则返回null
        // entry.boundingClientRect:目标元素的矩形区域的信息
        // entry.intersectionRect:目标元素与视口(或根元素)的交叉区域的信息
        // entry.intersectionRatio:根和目标元素的交叉区域的比例值,即intersectionRect占boundingClientRect的比例,0 为完全不可见,1 为完全可见
        // entry.isIntersecting:true表示从不可视状态变为可视状态。false表示从可视状态到不可视状态:false
    });
};

3. observer.observe(targetNode) 指定目标元素 targetNode1、targetNode2,开始观察。

//observe的参数是一个 DOM 节点对象。如果要观察多个节点,就要多次调用这个方法。
observer.observe(targetNode1);
observer.observe(targetNode2); //开始观察目标元素。
// observer.disconnect(); //关闭观察器。
// observer.takeRecords(); //返回所有观察目标对象数组。
// observer.unobserve(targetNode1); //停止观察特定目标元素。

实例1:图片懒加载

实例2:无限滚动

无限滚动时,在页面底部加一个footerSentinel元素。一旦footerSentinel可见,就表示页面滚动到了底部,从而加载新的条目放在footerSentinel前面。

const observer = new IntersectionObserver((entries, observer) => { 
    entries.forEach(entry => {
        if (entry.intersectionRatio <= 0) return; // 如果不可见,就返回
        let newData = [1,2,3,4,5];
        appendChildBeforeFooter(newData); //新数据追加在footerSentinel之前
    }) 
});

// 开始观察
observer.observe(
  document.querySelector('.footerSentinel')
);

实例3:网页广告的曝光量统计

很多时候,广告图片不一定需要全部展示才算被用户看到,有时候图片只展示了60%时,主要信息已经被用户看到,这种情况其实是可以算作一次曝光量的统计。为了实现这种广告的曝光量的精确统计,我们可以创建交叉管理器,观察到广告目标元素的交叉比例intersectionRatio达到0.6时,判定广告的曝光量+1

const intersectionObserver = new IntersectionObserver((entries)=> {
     entries.forEach(entry => {
         if(entry.intersectionRatio > 0){
            console.log('info:');
            console.log('广告位元素和可视区域相交部分的比例:'+entry.intersectionRatio + ',广告曝光量➕1')
            intersectionObserver.unobserve(document.querySelector('.DemoIntersectionObserver .ad'))
         }
     })
 },{ 
     threshold: 0.6,
 });
intersectionObserver.observe(document.querySelector('.DemoIntersectionObserver .ad'));

MutationObserver 变化观察器

该观察器"观察"目标元素属性和子节点的变化。目标元素DOM发生变动就会触发观察器的回调函数。注意:异步触发,DOM的变动并不会马上触发,而是要等到当前所有DOM操作都结束才触发。

兼容性:IE10+

基本用法

1. 通过 new MutationObserver(callback) 创建观察器实例 observer

let observer = new MutationObserver(callback); 

2. 定义观察到目标元素的特定变动时的回调函数 callback(mutationList, observer)mutationList为包含目标元素DOM变化相关信息的对象的数组,数组中,每个成员都是一个MutationRecord对象

let callback = (mutationList, observer)  => { 
    mutationList.forEach((mutation) => {
        console.log(mutation.target) //发生变动的DOM节点
        console.log(mutation.previousSibling) //前一个同级节点,如果没有则返回null。
        console.log(mutation.nextSibling) //下一个同级节点,如果没有则返回null。
        switch(mutation.type) {//目标元素变化类型'childList' || 'attributes' || 'characterData'
            case 'childList':
                console.log(mutation.addedNodes) //新增的 DOM 节点
                console.log(mutation.removedNodes) //删除的 DOM 节点
                break;
            case 'attributes':
                console.log(mutation.attributeName) //被更改的属性名称,如果设置了attributeFilter,则只返回预先指定的属性。
                console.log(mutation.oldValue) //该属性之前的值,这个属性只对attribute和characterData变动有效,如果发生childList变动,则返回null。
                break;
        }
    });
};

3. observer.observe(targetNode[, options]), 按照options配置指定要观察的特定变动,并开始观察目标元素 targetNode。其中:childList,attributes、characterData 三个DOM变动类型的属性之中,至少有一个必须为true,若均未指定将报错。

let targetNode = document.querySelector("#someElement");
let options = {
    childList: true,  //  DOM 变动类型:是否观察目标子节点添加或删除,默认为false。
    attributes: true, //  DOM 变动类型:是否观察目标节点属性变动,默认为false。
    characterData: false, //  DOM 变动类型:是否观察文本节点变化。无默认值
    subtree: true, // 是否观察后代节点,默认为false。
    // attributeOldValue: true, //表示观察attributes变动时,是否需要记录变动前的属性值。
    // characterDataOldValue: true, //表示观察characterData变动时,是否需要记录变动前的值。
    // attributeFilter: ['class','src'], //数组,表示需要观察的特定属性(比如['class','src'])。
}
observer.observe(targetNode, options); //开始观察目标元素
// observer.disconnect(); //停止观察。
// observer.takeRecords(); //返回所有观察目标对象数组。

ResizeObserver 大小观察器 (实验)

该观察器"观察"Element内容区域的改变或SVGElement的边界框的改变,每次元素内容或边框的大小变化时都会向观察者传递通知。

基本用法

1. 通过 new ResizeObserver(callback) 创建观察器实例 observer

let observer = new ResizeObserver(callback); 

2. 定义观察到目标元素的大小变化的回调函数 callback(entries, observer)entries为包含目标元素大小变化的相关信息的数组,数组中,每个成员都是一个ResizeObserverEntry对象

let callback = (entries, observer) => {
    entries.forEach(entry => {
        console.log('当前大小', `${entry.contentRect.width} x ${entry.contentRect.height}`)
        /**
         * entry.target :目标元素
         * entry.borderBoxSize: 包含目标元素的新边框框大小的对象
         * entry.contentBoxSize: 包含目标元素的新内容框大小的对象
         * entry.contentRect: 包含目标元素的新大小的对象
         * entry.devicePixelContentBoxSize 包含目标元素以设备像素为单位的新内容框大小的对象
         * */
    });
}

3. observer.observe(targetNode); 开始观察目标元素 targetNode

let targetNode = document.querySelector("#someElement");
observer.observe(targetNode);//开始观察目标元素
// observer.disconnect(); //停止观察。
// observer.unobserve(targetNode); //停止观察目标元素。

PerformanceObserver 性能观察器

该观察器用于“观察”记录 performance 数据的行为,一旦记录了就会触发回调,可以在回调里上报这些性能相关的数据。

浏览器API performance 用于记录一些时间点、某个时间段、资源加载的耗时等;附上:performance详细用法

基本用法

1. 通过 new PerformanceObserver(callback) 创建观察器实例 observer

const observer = new PerformanceObserver(callback) 

2. 定义观察到目标元素的特定变动时的回调函数 callback(list, observer)list.getEntries()为包含options中指定的相关performance数据的对象的数组,每个成员都是一个PerformanceEntry对象

let callback = (list, observer) => {
    list.getEntries().forEach(entry => {
        console.log(entry); //entry为按startTime排序的performance上报的数据对象,自动根据所请求资源的变化而改变,也可以用mark(),measure()方法自定义添加
        /**
         * entry.name:资源名称,是资源的绝对路径或调用mark方法自定义的名称
         * entry.entryType:资源类型,entryType类型不同数组中的对象结构也不同
         * entry.startTime:开始时间
         * entry.duration:加载时间
         * entry.entryType == 'paint' && entry.name == 'first-paint':'首次绘制,绘制Body',
         * entry.entryType == 'paint' && entry.name == 'first-contentful-paint':'首次有内容的绘制,第一个dom元素绘制完成',
         * entry.entryType == 'paint' && entry.name == 'first-meaningful-paint':'首次有意义的绘制',
        */
    });
}

3. observer.observe(options), 按照options配置,指定所要观察的performance数据相关变化。

let options = {
    entryTypes:[// 类型为string[],必填,且数组不能为空,数组中某个字符串取的值无效,浏览器会自动忽略它
        'longtask', // 长任务 (>50ms)
        'frame', // 帧的变化,常用于动画监听,使用时注意兼容
        'navigation', // 页面加载||刷新||重定向
        'resource', // 资源加载
        'mark',//  自定义记录的某个时间点
        'measure',//  自定义记录的某个时间段
        'paint'//  浏览器绘制
    ]
};
observer.observe(options); //当记录的性能指标在指定的 entryTypes 之中时,将调用性能观察器的回调函数。
// observer.disconnect(); //阻止性能观察器接收任何性能指标事件。
// observer.takeRecords(); //返回存储在性能观察器中的性能指标的列表,并将其清空。

ReportingObserver 报告观察器(实验)

该观察器“观察”过时的api、浏览器的一些干预行为报告,在回调里上报。

转载:一起认识下浏览器的5种观察器

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值