C端开发过程中的mv埋点, 要求元素暴露在视口内, 用户可见时才上报mv埋点,有一种做法是判断元素的滚动距离,人工判断是否元素滚动进入视口,金刚位滚动,轮播的交互方式下,还要处理上报过的不再次上报的逻辑,这种做法十分麻烦。
原文参考:https://developer.mozilla.org/zh-CN/docs/Web/API/Intersection_Observer_API
神器 :Intersection Observer API
是什么?
检测目标元素与祖先元素相交情况变化的api。
应用场景:
-
图片懒加载 ,当图片滚动到可见时才进行加载。
内容无限滚动 , 用户滚动到接近页面底部时直接加载更多,无需操作翻页。这个我以往的处理还是判断滚动距离+节流 : https://km.sankuai.com/page/716538605
在用户看到某个区域时,播放动画或执行任务。
工作机制:
Intersection Observer API 会注册一个回调函数,每当被监视的元素进入或者退出另外一个元素时(或者 <u>viewport</u> )设备视窗或者其他元素我们称它为根元素或根(root),或者两个元素的相交部分大小发生变化时,该回调方法会被触发执行。这样,我们网站的主线程不需要再为了监听元素相交而辛苦劳作,浏览器会自行优化元素相交管理。
注意 Intersection Observer API 无法提供重叠的像素个数或者具体哪个像素重叠,他的更常见的使用方式是——当两个元素相交比例在 N% 左右时,触发回调,以执行某些逻辑。
目标(target)元素与根(root)元素之间的交叉度是交叉比(intersection ratio)。这是目标(target)元素相对于根(root)的交集百分比的表示,它的取值在0.0和1.0之间。阈值为1.0意味着目标元素完全出现在root选项指定的元素中可见时,回调函数将会被执行。
用法:
创建一个 IntersectionObserver对象,并传入相应参数和回调用函数,该回调函数将会在目标(target)元素和根(root)元素的交集大小超过阈值(threshold)规定的大小时候被执行。
传递到<u>IntersectionObserver()</u>构造函数的 options 对象,允许您控制观察者的回调函数的被调用时的环境。我使用时只用了threshold,它可以有以下字段:
root
指定根(root)元素,用于检查目标的可见性。必须是目标元素的父级元素。如果未指定或者为null,则默认为浏览器视窗。
rootMargin
根(root)元素的外边距。类似于 CSS 中的 <u>margin</u> 属性,比如 "10px 20px 30px 40px" (top, right, bottom, left)。如果有指定root参数,则rootMargin也可以使用百分比来取值。该属性值是用作root元素和target发生交集时候的计算交集的区域范围,使用该属性可以控制root元素每一边的收缩或者扩张。默认值为0。
threshold
可以是单一的number也可以是number数组,target元素和root元素相交程度达到该值的时候IntersectionObserver注册的回调函数将会被执行。如果你只是想要探测当target元素的在root元素中的可见性超过50%的时候,你可以指定该属性值为0.5。如果你想要target元素在root元素的可见程度每多25%就执行一次回调,那么你可以指定一个数组[0, 0.25, 0.5, 0.75, 1]。默认值是0(意味着只要有一个target像素出现在root元素中,回调函数将会被执行)。该值为1.0含义是当target完全出现在root元素中时候 回调才会被执行。
intoView() {
this.$nextTick(()=>{
const items = document.querySelectorAll(".service-item-icon")
const io = new IntersectionObserver(entries => {// step1:创建一个 IntersectionObserver对象,并传入相应参数和回调用函数
entries.forEach(entry => {
try{
if(entry.intersectionRatio > 0) {
io.unobserve(entry.target) // 移除当前元素的监听器,实现上报过的不再次上报。
someFunction() // 执行一些逻辑
}
}catch(e){
throw e
}
})
}, {
threshold: [0.1] // options。回调函数将会在目标(item)元素和父元素的交集大小超过阈值10%时候被执行。
})
items.forEach(node => {
io.observe(node) // 开始观察
})
})
}
当时遇到的困惑:
1:文档中说,当交集发生变化时才会触发callback,但是打印结果却是全量的,为什么?
解答: MDN中写道:回调函数的触发情况有两种:
a. 当目标元素与视窗或其他指定元素发生交集时候执行。
b. Observer第一次监听目标元素的时候。
所以,此处的console打印全量是因为所有的item都开始被observe监听了。
(由于此处的解释和阮一峰老师的说法有差异,产生了一些误解,但实验结果表明,mdn解释的是符合现象的。)
阮: