实现图片懒加载的新方式-IntersectionObserver

这是我参与更文挑战的第12天,活动详情查看: 更文挑战

图片懒加载

定义

什么是图片懒加载? 是一种提升页面加载速度的优化方式

假设我们页面有很多图片,如果我们一进入页面就加载所有图片,现在的图片都有几百k,那加载完耗时就很久,用户都跑光了图片还没加载好,所以就有图片懒加载这种方式

图片懒加载,就是页面向下滚动,当图片快到我们的可视区域之前,才去加载图片,不在我们的可视区域我们就不加载,这就是图片懒加载,可以更好的节省带宽,提高页面加载速度。

常规实现方法

一般常规的实现方法,是监听页面的滚动事件,在快要滚动到图片的位置之前,把img的src替换成真实的src,后面的图片依次类推。简易版代码如下

    // 检查是否在可视区域
    function checkDomIsInVisibleArea(dom) {
      // 间距,就是提前多少间距就认为是在可视区域里面
      const distance = 100
      const rect = dom.getBoundingClientRect()
      return rect.top < window.innerHeight + distance && rect.top > -distance && rect.left < window.innerWidth + distance && rect.left > -distance
    }
    // 防抖函数
    function debounce(fn, delay = 100) {
      let timer = null
      return function (...args) {
        if (timer) clearTimeout(timer)
        timer = setTimeout(() => {
          fn(...args)
        }, delay)
      }
    }
    // 懒加载
    function lazyLoad() {
      const imgs = document.querySelectorAll('img')
      imgs.forEach(dom => {
        // 在可视区域并且有data-src
        if (checkDomIsInVisibleArea(dom) && dom.dataset['src']) {
          dom.setAttribute('src', dom.dataset['src'])
          dom.removeAttribute('data-src')
        }
      })
    }
    // 监听滚动事件
    window.addEventListener('scroll', debounce(lazyLoad))
复制代码

今天看到还有一个原生api有个神器也可以实现,那就是IntersectionObserver,下面咱们好好来讲讲。

IntersectionObserver

翻译为交叉观察者,可以异步观察目标元素与其祖先元素或顶级文档视窗(viewport)的交叉状态,简而言之就是监听元素,如果该元素处于可视区域或者滚动经过可视区域,会触发回调函数。

IntersectionObserver API是异步的,不随着目标元素的滚动同步触发,不用担心会影响网页性能

语法

const observer = new IntersectionObserver(callback[, options]) // 返回 IntersectionObserver实例

callback
如果元素和祖先元素发生交叉,就执行此回调函数,返回2个参数

  1. entries,包含IntersectionObserverEntry对象的数组

    打印的IntersectionObserverEntry对象
    image.png

    IntersectionObserverEntry对象说明如下

    属性 说明
    boundingClientRect 目标元素的位置信息
    intersectionRatio 目标元素在可视区域的占比
    intersectionRect 目标元素与可视区域的交叉位置信息
    isIntersecting 目标元素是否正在可视区域
    rootBounds 可视区域的位置信息
    target 目标元素
    time 记录时间原点到发生交叉的时间戳,毫秒

options

可选,对象类型,配置参数如下

属性 说明
root 当作可视区域的Element对象,默认是浏览器的视口
rootMargin 扩大或者缩小可视区域的的大小,语法大致和CSS中的margin属性等同,默认是0px 0px 0px 0px
threshold 规定了目标元素占可视区域多大比例,才触发callback,可以是数值或者数组。默认是0, 就是监听元素一出现在可视区域就触发,最大是1, 整个元素都出现了才触发。也可以设置数组,[0, 0.25, 1], 一进入触发(0%)回调,当进入到25%时候触发回调,整个元素都出现(100%)也触发回调

IntersectionObserver实例方法

  1. observe(Element)

    开始监听一个目标元素, 参数是目标元素的节点

  2. unobserve(Element)

    取消监听一个目标元素, 参数是目标元素的节点

  3. takeRecords()

    无参数,返回所有目标元素的IntersectionObserverEntry对象的数组

  4. disconnect()
    无参数,断开连接,停止IntersectionObserver的所有监听

图片懒加载-IntersectionObserver实现

    // 创建交叉观察实例
    const observer = new IntersectionObserver(entries => {
      entries.forEach(item => {
        // 如果正在交叉
        if (item.isIntersecting) {
          item.target.setAttribute('src', item.target.dataset['src'])
          // 取消监听
          observer.unobserve(item.target)
        }
      })
    }, {
      threshold: .1
    })
    const imgs = document.querySelectorAll('img')
    // 遍历imgs开始监听
    imgs.forEach(item => {
      // 开始监听
      observer.observe(item)
    })
复制代码

兼容性

目前兼容性不是很好,查看下图,数据来自caniuse

image.png

总结

IntersectionObserver这个api很好用,图片懒加载只是其中的一个用法,还可以用来无限滚动,曝光埋点滚动动画等等,大家先学会,后面有需要就可以用上啦,希望对你们有帮助。感谢~

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享