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、浏览器的一些干预行为报告,在回调里上报。