浅谈IntersectionObserver

61 阅读4分钟

浅谈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的异步组件 最后一句

学习心得!若有不正,还望斧正。希望掘友们不要吝啬对我的建议。