浅谈IntersectionObserver API
要检测一个元素是否可见或者两个元素是否相交并不容易,很多解决办法不可靠或性能很差。实现方式很丑陋,也极易拖慢整个网站的性能。IntersectionObserver API会注册一个回调函数,每当被监视的元素进入或者退出另外一个元素时,或者两个元素的相交部分大小发生变化时,该回调方法会被触发执行。这样,我们网站的主线程不需要再为了监听元素相交而辛苦劳作,浏览器会自行优化元素相交管理。
API解读:
Intersection Observer API 允许你配置一个回调函数,当以下情况发生时会被调用
- 每当目标 (target) 元素与设备视窗或者其他指定元素发生交集的时候执行。设备视窗或者其他元素我们称它为根元素或根 (root)。换言之,设备视窗或者其他指定元素看作可视区,当目标元素出现在可视区的时候触发回调函数。
- Observer 第一次监听目标元素的时候,换言之,当我们指定谁为目标元素时,触发回调函数。
Intersection Observer API 允许你配置的其他参数
root:根元素
所监听的指定元素。如果未传入值或值为
null
,则默认使用顶级文档的视窗(一般为html)。rootMargin:矩形偏移量
可以有效的缩小或扩大根的判定范围从而满足计算需要。所有的偏移量均可用像素(
px
)或百分比(%
)来表达, 默认值为"0px 0px 0px 0px"。thresholds:阈值
回调函数将会在目标 (target) 元素和根 (root) 元素的交集大小超过阈值 (threshold) 规定的大小时候被执行。
默认值是 0 (意味着只要有一个 target 像素出现在 root 元素中,回调函数将会被执行)。
阈值为 1.0 (意味着目标元素完全出现在 root 选项指定的元素中可见时,回调函数将会被执行)。
也可以是 number 数组。[0, 0.25, 0.5, 0.75, 1](意味着target 元素在 root 元素的可见程度每多 25% 就执行一次回调)
const io = new IntersectionObserver(callback, options)
const options = {
root: null,
rootMargin: 0,
thresholds: 1,
}
const callback = (entries)=>{
console.log(entries)
}
const io = new IntersectionObserver(entries => {
// Do something
}, options)
observe()
创建一个 IntersectionObserver 实例后需要给定一个目标元素进行观察。
每当目标元素满足该 IntersectionObserver 指定的 threshold 值,回调被调用。
let DOM = document.querySelector('#listItem');
io.observe(DOM)
IntersectionObserverEntry
每当触发回调函数,回调接收IntersectionObserverEntry对象和观察者的列表
let callback =(entries, observer) => {
entries.forEach(entry => {
const {
boundingClientRect,// 返回包含目标元素的边界信息,返回结果与element.getBoundingClientRect() 相同
intersectionRatio,// 返回目标元素出现在可视区的比例
intersectionRect,// 用来描述root和目标元素的相交区域
isIntersecting,// 返回布尔值,如果目标元素出现在root可视区,返回true。如果从root可视区消失,返回false
rootBounds,// 用来描述交叉区域观察者(intersection observer)中的根.
target,// 目标元素:与根出现相交区域改变的元素 (Element)
time,// 返回一个记录从 IntersectionObserver 的时间原点到交叉被触发的时间的时间戳
} = entry
});
}
unobserve()
停止监听特定目标元素
let DOM = document.querySelector('#listItem');
io.unobserve(DOM)
takeRecords()
返回所有观察目标的IntersectionObserverEntry对象数组
disconnect()
使IntersectionObserver对象停止全部监听工作
示例
- 图片懒加载——当图片滚动到可见时才进行加载
const imgList = [...document.querySelectorAll('img')]
var io = new IntersectionObserver((entries) =>{
entries.forEach(item => {
// isIntersecting是一个Boolean值,判断目标元素当前是否可见
if (item.isIntersecting) {
item.target.src = item.target.dataset.src
// 图片加载后即停止监听该元素
io.unobserve(item.target)
}
})
}, {
root: document.querySelector('.root')
})
// observe遍历监听所有img节点
imgList.forEach(img => io.observe(img))
- 内容无限滚动——也就是用户滚动到接近内容底部时直接加载更多,而无需用户操作翻页,给用户一种网页可以无限滚动的错觉
- 检测广告的曝光情况——为了计算广告收益,需要知道广告元素的曝光情况
const boxList = [...document.querySelectorAll('.box')]
var io = new IntersectionObserver((entries) =>{
entries.forEach(item => {
// intersectionRatio === 1说明该元素完全暴露出来,符合业务需求
if (item.intersectionRatio === 1) {
// 。。。 埋点曝光代码
io.unobserve(item.target)
}
})
}, {
root: null,
threshold: 1, // 阀值设为1,当只有比例达到1时才触发回调函数
})
// observe遍历监听所有box节点
boxList.forEach(box => io.observe(box))
- 在用户看见某个区域时执行任务或播放动画
- vue的异步组件
最后一句
学习心得!若有不正,还望斧正。希望掘友们不要吝啬对我的建议。