用一个简单的方法实现图片懒加载...

653 阅读4分钟

场景

这期接了一个抽奖模块重构的需求,由于页面的产品列表是由后端返回的一整张图片,加上背景图和banner图导致页面首次加载非常慢,可以说是忍受不了的卡顿,网上扒着看了看如何优化,基本毫无疑问首当其冲的就是图片懒加载了。可是,图片懒加载的话会导致不停的监听scroll滚动事件,浪费性能,而且需要计算各种距离去判断,这样多次循环势必会导致性能消耗更大,有没有更好的方法呢,当然是有,也看到一些博主分享了一个新的APIIntersection Observer,于是决定下功夫把它给研究透,接下来记录一下学习的过程:

介绍

第一步当然是查看我们的官方文档MDN啦,接下来我一步一步的介绍一下如何使用这个api完成简单懒加载的实现

image.png 解释: 意思就是使用这个api可以检测到你绑定的元素与祖先元素是否相交,即可以理解为是否出现在可视区内。这个api功能还是很强大的,可以实现图片懒加载 数据懒加载 以及虚拟滚动列表都可以用它来完成

使用方法

  1. 创建一个IntersectionObserver 实例,接收两个参数callbackoptions. callback函数会在绑定元素出现在可视区的时候执行,options是一个可选参数集合,分别是root rootmargin threshold.

    let obi = new IntersectionObserver(callback, {
        root: document.querySelector('#root'),
        rootMargin: '0px',
        threshold: 0
    })
    
  • root 参数指定根元素,用于检查目标元素的可见性,即你要获得目标元素与哪个元素的交叉,不指定则默认为浏览器视窗

  • rootmargin 根元素的外边距。用来计算当目标元素与根元素发生交叉的时候控制根元素每一个边的收缩或者扩张的,与css中的margin一个意思

  • threshold 取值0~1之间,也可以是一个数组,用以指定目标元素与根元素 相交到什么程度去执行回调函数的,0则代表一出现在视口就会执行,1代表完全显示在视口范围才去执行回调。如果你要目标元素与根元素每相交某个比例就执行一次,那么可以指定一个数组 [0, 0.25. 0.5, 0.75, 1].

  • callback函数接收两个参数,一个是entries被观察的元素信息对象的数组 [{元素信息},{}],对象中isIntersecting属性可以判断进入或离开,true代表在可视区,false代表离开可视区,其他的属性暂时没用到没有仔细去了解;另外一个参数是观察者实例 observer. 实例上有几个方法可以,分别是 observer.observe() 开始监听 和 observer.unobserve()停止监听,估计目前大家用到的也就这两个方法了,还有其他的可以自己查阅下。

代码实现

介绍完了这个API,话不多说,直接上代码吧,写了一个简单的图片懒加载的指令

// 定义指令
// <img :src="item.src" alt="" />
// <img v-lazy="item.src" alt="" />
vue.directive('lazy', {
  inserted(el, { value }) {
    // 图片的懒加载逻辑
    // 参数1:回调函数
    // 参数2:可选的配置
    const observer = new IntersectionObserver(
      ([{ isIntersecting }], observer) => {
        if (isIntersecting) {
          // 停止监听
          observer.unobserve(el)
          // 给el元素设置src属性
          // value = '123.jpg'
          el.src = value
          // 如果图片加载失败,显示默认的图片
          el.onerror = function() {
            el.src = require('@/assets/images/error.png')
          }
        }
      },
      {
        threshold: 0
      }
    )
    observer.observe(el)
  }
})

兼容性的说明

由于是线上的移动端app项目当然要考虑到万无一失喽,新的API虽好用,不用像以前那样去计算各种距离 再去循环判断了,但是这个API在ios Safari上只支持12.1以上的浏览器版本

image.png

搞到这里有种前功尽弃的感觉,再好不能用有什么区别,不甘心再去写一个老方法去循环的判断计算元素是否在可视区,于是我查阅了Safari 12.1以上是运行在ios第几个版本里面,百度了半天也没用找到关于Safari和ios系统对应的系统版本关系,无奈之下又去问了公司开发ios的同事才得知Safari版本跟着系统走的,为了确定准确无误,去了一些国外论坛找到了对应版本关系,基本可以确定ios版本是和Safari版本一样对应的了。注意: 此API只在ios12.2以上的系统中可以使用,考虑兼容12.2以下系统的就放弃吧果断

提示:我查阅了ios13和14的安装率,基本都在百分之九十以上了,又查阅了ios12系统支持的苹果手机,得知支持到iPhone6,查阅一些文档得知ios14系统发布后三个月,在过去四年推出的iPhone中,有81%安装了“ iOS 14”;有17%继续运行iOS 13;另外2%运行更早版本的iOS,所以2%的用户更早的ios版本 几乎可以忽略不计

到此,完美使用此API,丝毫不慌,实在担心的小伙伴可以写一个兼容的方法