交叉观察器 IntersectionObserver

478 阅读4分钟

IntersectionObserver API提供了一种异步检测目标元素与祖先元素或 viewport 相交情况变化的方法。

过去,要检测一个元素是否可见或者两个元素是否相交并不容易,很多解决办法不可靠或性能很差。然而,随着互联网的发展,这种需求却与日俱增,比如,下面这些情况都需要用到相交检测:

  • 图片懒加载——当图片滚动到可见时才进行加载
  • 内容无限滚动——也就是用户滚动到接近内容底部时直接加载更多,而无需用户操作翻页,给用户一种网页可以无限滚动的错觉
  • 检测广告的曝光情况——为了计算广告收益,需要知道广告元素的曝光情况
  • 在用户看见某个区域时执行任务或播放动画

\

\

传统的实现方法是,监听到scroll事件后,调用目标元素的getBoundingClientRect()方法,得到它对应于视口左上角的坐标,再判断是否在视口之内。这种方法的缺点是,由于scroll事件密集发生,计算量很大,容易造成性能问题。

目前有一个新的 IntersectionObserver API,可以自动"观察"元素是否可见。由于可见(visible)的本质是,目标元素与视口产生一个交叉区,所以这个 API 叫做"交叉观察器"。

\

一、API

它的用法非常简单。

let io = new IntersectionObserver(callback, option);

上面代码中,IntersectionObserver是浏览器原生提供的构造函数,接受两个参数:callback是可见性变化时的回调函数,option是配置对象(该参数可选)。

构造函数的返回值是一个观察器实例。实例的observe方法可以指定观察哪个 DOM 节点。

// 开始观察

io.observe(document.getElementById('example'));

// 停止观察

io.unobserve(element);

// 关闭观察器

io.disconnect();

上面代码中,observe的参数是一个 DOM 节点对象。如果要观察多个节点,就要多次调用这个方法。

io.observe(elementA);

io.observe(elementB);

\

二、callback 参数

目标元素的可见性变化时,就会调用观察器的回调函数callback。

callback一般会触发两次。一次是目标元素刚刚进入视口(开始可见),另一次是完全离开视口(开始不可见)。

var io = new IntersectionObserver(

entries => {

console.log(entries);

}

);

。callback函数的参数(entries)是一个数组,每个成员都是一个IntersectionObserverEntry对象。如果同时有两个被观察的对象的可见性发生变化,entries数组就会有两个成员。

\

三、IntersectionObserverEntry 对象

IntersectionObserverEntry对象提供目标元素的信息,一共有六个属性。

\

time:可见性发生变化的时间,是一个高精度时间戳,单位为毫秒

\

isIntersecting: 返回一个布尔值,如果目标元素与根元素相交,则返回 true ,如果 isIntersecting 是 true,则 target 元素至少已经达到 thresholds 属性值当中规定的其中一个阈值,如果是 false,target 元素不在给定的阈值范围内可见。

\

target:被观察的目标元素,是一个 DOM 节点对象

\

rootBounds:根元素的矩形区域的信息,getBoundingClientRect()方法的返回值,如果没有根元素(即直接相对于视口滚动),

\

boundingClientRect:目标元素的矩形区域的信息

\

intersectionRect:目标元素与视口(或根元素)的交叉区域的信息

\

intersectionRatio:目标元素的可见比例,即intersectionRect占boundingClientRect的比例,完全可见时为1,完全不可见时小于等于0

\

四、option参数

root: 设置目标元素的根元素,也就是我们用来判断元素是否可见的区域,必须是目标元素的父级元素,如果未指定或者为null,则使用浏览器视窗,也就是 document。

\

rootMargin: 一个在计算交叉值时添加至根的边界中的一组偏移量,类型为字符串 (string) ,可以有效的缩小或扩大根的判定范围从而满足计算需要。语法大致和CSS 中 margin 属性等同,默认值 “0px 0px 0px 0px” ,如果有指定 root 参数,则 rootMargin 也可以使用百分比来取值。

\

threshold: 介于 0 和 1 之间的数字,指示触发前应可见的百分比。也可以是一个数字数组,以创建多个触发点,也被称之为 阈值。如果构造器未传入值, 则默认值为 0 。

\

trackVisibility: 一个布尔值,指示当前观察器是否将跟踪目标可见性的更改,默认为 false ,注意,此处的可见性并非指目标元素和根元素是否相交,而是指视图上是否可见,这个我们之前就已经分析过了,如果此值设置为 false 或不设置,那么回调函数参数中 IntersectionObserverEntry 的 isVisible 属性将永远返回 false 。

\

delay: 一个数字,也就是回调函数执行的延迟时间(毫秒)

\

react: react-intersection-observer

\