最近经常遇到检查可视区域元素的场景,以前作者都用scroll事件和getBoundingClientRect方法,当然还需要为scroll事件加一下节流,否则会有性能问题。后来发现同事们有的用IntersectionObserver,这个API出来有几年了,不过一直没怎么用,这篇文章总结一下。
直接用demo验证这个API
![8decad9be7ff8dca3b81406d82d5eeca.png](https://i-blog.csdnimg.cn/blog_migrate/573f6d7f96973c24741a87d62b36d068.jpeg)
图1
如果图1,用ul+li做出一个可滚动的页面,用红色边框区分每个li。我们现在就监控哪些li出现在了可视区。
![d3cd05711c41ef83cc61b03fcfa1b453.png](https://i-blog.csdnimg.cn/blog_migrate/440c8187441ff950c144d975cbb6ae38.jpeg)
图2
如图2,用法非常简单,new一个IntersectionObserver实例,参数是一个回调函数,回调函数被触发仅出现在被监听的元素出现或者不出现在可视区域内这两个时机。
使用observer方法指定被监控的元素,可以监控很多个,上图中我们把所有的li元素都监控了,其中任何一个元素可视性发生改变都会触发IntersectionObserver实例的回调函数。回调函数的参数返回了可视性发生变化的dom元素的数据,这个参数是数组类型,数组的每个元素都是IntersectionObserverEntry对象。
![d841a5d8e72f35791fba7b8276d80900.png](https://i-blog.csdnimg.cn/blog_migrate/392b8e8a42ac1006a113a212fa158aa7.jpeg)
图3
如图3,我们打印出其中一个IntersectionObserverEntry对象,可以发现它有以下几个参数,
(1)time,可见性发生变化时的时间,单位为毫秒;
(2)target,可见性发生变化的dom元素;
(3)intersectionRatio,可见性发生变化时目标元素可见区域面积与整个元素面积的比值,可以用它来判断元素是否可见;
(4)isIntersecting,是否出现在可视区,也可以用它来判断是否可见;
(5)isVisible,这个属性看字面意思是是否可见,但经测试一直无变化,暂且不知其用法;
(6)rootBounds、boundingClientRect、intersectionRect这三个属性分别代表三种矩形区域的信息,如下:
![4982340922bffc19172df017618defe8.png](https://i-blog.csdnimg.cn/blog_migrate/f6a120076d95cfbf2fc1784ede24e281.jpeg)
图4
如图4,每个矩形区域提供8个属性,他们表示的意义和之前用getBoundingClientRect方法获取的数据意义相同。
![4555e9d3da7f3bd0d0b46e9cae6f941b.png](https://i-blog.csdnimg.cn/blog_migrate/72330b31084f2958b3e730caf101b802.jpeg)
图5
x、y代表坐标,坐标原点是滚动容器的左上角顶点,所有的数据都是元素可见性发生变化的那一瞬间的值。
rootBounds:代表滚动元素容器的矩形区域
boundingClientRect:代表被监控元素的矩形区域
intersectionRect:代表被监控元素暴露在可视区内的矩形区域部分
在IntersectionObserver实例化时还可以传入第二个配置参数,如下:
![92cfdb00efa7d3ad0664e755bde78e34.png](https://i-blog.csdnimg.cn/blog_migrate/02940690a9c6f8dda1927875153fe1c4.jpeg)
图6
如果是页面中某个元素作为滚动的容器,如图6,可以用root属性配置。这时就会出现一种情况,滚动容器可能不在视窗内,但它内部元素依然可滚动,此时实例的回调依然会触发,所以回调会不会被执行并不在于肉眼是否可见,而在于被监控的元素和滚动容器的交叉部分是否发生变化。仔细看API的英文单词IntersectionObserver,翻译过来就是交集区域观察。
目前的情况是出现或者不出现时触发回调,但是我们可以使用threshold属性设置交集区域的比例,达到这个比例才触发回调。
![ff604721ac27ba34d9161beb44c91c7c.png](https://i-blog.csdnimg.cn/blog_migrate/41875574813944a42a3e2ec909e8ec22.jpeg)
图7
如图7,可以一次性定义多个交叉比例,滚动时在每个比例处都会触发。
rootMargin属性还可以扩大或者缩小rootBounds的大小,如下图所示
![0806c2cd9dcb8d98d491684dddd057cb.png](https://i-blog.csdnimg.cn/blog_migrate/f15906e8155d018ccc3f628f24a4132b.jpeg)
图8
![7cfcd30652d982c9a92542cc9d8da858.png](https://i-blog.csdnimg.cn/blog_migrate/b7efa7a6fb776e5a6014422634bdf3d5.jpeg)
图9
如图8和9,我们设置了rootMargin为10px,虽然滚动容器的尺寸没变化,但rootBounds向四周扩展了10px,这个属性的主要作用是提前或者延迟回调的触发,它的用法和margin一致。
![1cae7e0c197896f4c07258f5d5728f36.png](https://i-blog.csdnimg.cn/blog_migrate/124e4c911a1cea7418cf3bf527669767.jpeg)
图10
能绑定监控,就要能去移除监控,如图10所示,unobserve方法可以移除特定被监控的元素,disconnect方法可以直接关闭观察器,所有的元素都不会再被监控。
总结
这个API用起来很方便,回调中拿到的信息也十分丰富,但是兼容性需要注意一下。对于一些优化性质或者兼容性要求不高的项目可以尝试使用。
喜欢我的文章就关注我吧,有问题可以发表评论,我们一起学习,共同成长!