在vue中实现图片懒加载,并引入promise判断加载状态和优化

为什么需要懒加载?
答: 当你的一个网页,图片有几十张,上百张时,同时的加载,有可能会导致网页出现很长一段时间的空白,而且用户并不一定会浏览全部的图片,全部加载完,也会浪费用户的浏览,这样的体验是很不好的.

效果如图:
在这里插入图片描述
那么如何在vue项目中实现懒加载呢?

1.懒加载的原理
一张图片就是一个img标签,浏览器是根据src的属性发起图片请求的.那么我们实现的依据就是当前图片出现在可视屏幕上,就把图片的地址赋值(或替换)给img的src属性.

2.懒加载的实现步骤
2.1 默认loading图片
2.2 判断哪些需要加载(难点)
2.3 预缓存在浏览器
2.4 替换真图片

3.代码实现
3.1 默认loading图片
loading找一些1-2K的图片,越小越好,放置在本地assets目录即可

<template>
  <div class="img-loading-container" ref="imgBox">
    <img
      v-for="(item,index) in 5"
      :key="index"
      src="@/assets/loading.gif"
      alt=""
    >
  </div>
</template>

3.2 判断哪些需要加载
当图片进入可视区域时,应用网友的一张图
在这里插入图片描述
如上图所示, 当图片(指当前需要加载的图片)距离顶部的距离小于可视区域h和滚动区域高度s之和时说明图片进入可视化区域了,即top-height < s+h时,图片在可视区。
介绍用到的api函数:
网页被卷去的高: document.body.scrollTop;
可视区域高度: window.innerHeight
当前对象到浏览器顶部的距离: domObject.offsetTop

具体代码:

<script>
export default {
  data () {
    return {
      imgList: [
        {
          url: 'https://.../distribution-web/upLoad/img/ceshi/1.jpg'
        },
        {
          url: 'https://.../distribution-web/upLoad/img/ceshi/2.jpg'
        },
        {
          url: 'https://.../distribution-web/upLoad/img/ceshi/3.jpg'
        },
        {
          url: 'https://.../distribution-web/upLoad/img/ceshi/4.jp' // 这是故意写错的
        },
        {
          url: 'https://.../distribution-web/upLoad/img/ceshi/5.jpg'
        }
      ],
      present: {
        old: -1,
        new: 0
      }
    }
  },
  mounted () {
    // 进入当前页面就加载
    setTimeout(this.getImgList, 300)
    // 监听滚动事件
    window.addEventListener('scroll', this.getImgList)
  },
  methods: {
    getImageCache (imgNodes, id) {
      return new Promise((resolve, reject) => {
        // 创建一个image对象
        var temp = new Image();
        // 预先把加载的图片加入内存中(隐形加载),相当于给浏览器缓存了一张图片
        temp.src = this.imgList[id].url
        // 成功的状态
        temp.onload = () => {
          imgNodes[id].src = temp.src
          resolve('第' + (id + 1) + '张图片加载成功')        };
        // 失败的状态
        temp.onerror = () => reject('第' + (id + 1) + '张图片加载失败了');
      })
    },
    getImgList () {
      // 获取所有img的DOM对象
      const imgNodes = this.$refs.imgBox.childNodes
      // 可视区域高度
      const h = window.innerHeight;
      // 滚动区域高度
      const s = document.documentElement.scrollTop || document.body.scrollTop;

      for (let i = this.present.new; i < imgNodes.length; i++) {
        // 可视区域和滚动区域之和时懒加载大于图片距离顶部的距离
        if ((h + s) > imgNodes[i].offsetTop) {
          // 已加载的最大下标赋值给present做记录,防止再循环
          this.present.new = i
          // 当加载的最大下标值和上一次的下标值相等时,防止再请求
          if (this.present.old !== this.present.new) {
            this.getImageCache(imgNodes, i).then((success) => {
              console.log(success)
            }).catch((error) => {
              console.log(error)
              imgNodes[i].src = require('@/assets/error.jpg')
            })
            // 把当前最大下标值赋值给上一次最大下标值
            this.present.old = this.present.new
          }
        }
      }
    }
  }
}
</script>

你们可能会遇到的问题(因为我遇到过…)
1.当图片的height的数值设置为auto时,你会发现domObject.offsetTop(当前对象到浏览器顶部的距离)的值很小,然后你用domObject.offsetHeight(获取dom对象的高度)发现值为0!,解决方法有加个一次性计时器,还有就是放置在temp.onload中
2. 当你运用我的代码,打开浏览器的调试network时,每一张图片居然会加载两次或者很多次! 你再仔细看看你加载图片的Request Headers的两个属性,分别是cache-control和pragma。 他们的值都为no-cache(禁止缓存),这就是你浏览器的设置问题了,你在Disable cache打了勾,去掉就行了,如图
在这里插入图片描述

**最后:**本文章参考了tomorrownan的博客,后根据自己的思路,改造成vue的写法和加入promise,及把遇到的问题(已解决)分享给大家。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值