IntersectionObserver可以监听一个元素和可视区域相交部分的比例,然后在可视比例达到某个阈值的时候触发回调非常适合用在于滚动相关的交互事件中,例如:图片懒加载、无限滚动加载等。

用法

new IntersectionObserver(callback, options)

  1. // 创建要观察的目标元素
  2. const targetElement = document.getElementById('target');
  3. // 定义options对象,设置观察环境
  4. const options = {
  5. root: document.querySelector('#scrollArea'),
  6. // 指定根元素,用于检查目标的可见性。必须是目标元素的父级元素。如果未指定或者为null,则默认为浏览器视窗。
  7. rootMargin: '0px',
  8. // 使用类似于设置CSS边距的语法来指定根边距(根元素的观察影响范围)
  9. threshold: 0.3
  10. // 阈值,可以是单一的 number 也可以是 number 数组。
  11. // target 元素和 root 元素相交程度达到该值的时候 IntersectionObserver 注册的回调函数将会被执行。
  12. }
  13. // 设置回调函数
  14. const callback =(entries, observer) => {
  15. entries.forEach(entry => {
  16. // 每个成员都是一个IntersectionObserverEntry对象。
  17. // 举例来说,如果同时有两个被观察的对象的可见性发生变化,entries数组就会有两个成员。
  18. // entry.boundingClientRect
  19. // entry.intersectionRatio
  20. // entry.intersectionRect
  21. // entry.isIntersecting
  22. // entry.rootBounds
  23. // entry.target
  24. // entry.time
  25. if(entry.isIntersecting){
  26. // 元素进入可视区
  27. }
  28. });
  29. };
  30. var myObserver = new IntersectionObserver(callback, options)
  31. myObserver.observe(targetElement);

参数和属性

callback: 触发交叉的回调函数,接收一个entries参数,是一个IntersectionObserverEntry对象数组,提供了观察元素的信息,介绍几个常用的属性:

  • boundingClientRect:当前观察元素的矩形区域,类似getBoundingClientRect()
  • intersectionRatio:当前元素被交叉的比例。
  • intersectionRect:和视区交叉的矩形大小。
  • isIntersecting:true表示元素进入可视区内,false反之。
  • target:当前交叉的元素。

    交叉可以理解为监听的目标元素在视图中可见。 注意:页面初始化的时候会触发一次callback,entries为所有已监听的目标集合

options: 配置项,可选。

  • root:监听对象的祖先元素,默认是浏览器窗体元素。
  • rootMargin:检测区域的偏移量,默认“0px 0px 0px 0px”上右下左,正数值会增大视图区的检测范围,负值会缩小范围。

例如:设置rootMargin为”20px 0px 30px 30px”,如图此时滚动元素并未到达视窗,但已经切换为可见状态了:
image.png

  • threshold:阈值数组, 按升序排列, 范围为[0, 1.0]每个阈值都表示监听对象的交叉区域与边界区域的百分比。当监听对象的任何阈值被越过时,都会触发一次callback回调。如果构造器未传入值, 则默认值为0。

方法

IntersectionObserver.disconnect() 停止监听工作。
IntersectionObserver.observe() 开始监听一个目标元素。
IntersectionObserver.observe(targetElement);
此元素必须是根元素的后代 (如果根元素为视窗,则该元素必须被当前文档包含)。
IntersectionObserver.takeRecords() 返回所有观察目标的IntersectionObserverEntry对象数组。
IntersectionObserver.unobserve() 停止监听特定目标元素。

示例

图片懒加载

点击查看【codepen】

无限滚动加载

点击查看【codepen】

兼容性

IE浏览器不兼容,但是官方提供了polyfill

image.png

对比scroll事件

相比监听scroll事件,在频繁触发的scroll事件中访问元素的scrollTop、getBoundingClientRect等属性方法会频繁触发回流,非常消耗性能。而IntersectionObserver的回调是异步触发,不会随着目标元素的滚动而触发,性能消耗较低。

注意

IntersectionObserver API 是异步的,不随着目标元素的滚动同步触发。 规格写明,IntersectionObserver的实现,应该采用requestIdleCallback(),即只有线程空闲下来,才会执行观察器。这意味着,这个观察器的优先级非常低,只在其他任务执行完,浏览器有了空闲才会执行。

TIPS

在业务中,我们经常会做一些关于埋点上报的需求,比如一些页面展示时上报、按钮点击时上报等等。当需要元素曝光时上报就比较麻烦了,元素层级关系复杂可能会涉及到大量的计算,严重时可能影响页面性能。我们可以用IntersectionObserver解决这个问题。

参考:
https://developer.mozilla.org/zh-CN/docs/Web/API/IntersectionObserver
https://juejin.cn/post/6844903926815277069#comment
http://www.ruanyifeng.com/blog/2016/11/intersectionobserver_api.html