vue项目 利用异步特性实现图片懒加载

15 篇文章 0 订阅

一、前言

标题中写的“vue 项目...“,虽然确实是在vue项目中写的,但其实这篇文章主要讲的是一个思路,无论是不是在vue中,都是这个道理。

二、当前情况简单介绍

本文的懒加载是针对如下情况:通过调用接口,获取当页的用户信息(包括用户头像)。但这个时候数据中的头像不能直接通过<img>展示出来,而是需要先调用接口转为base64 ,例如:<img src="https://img-blog.csdnimg.cn/2022010618450173123.png"/> 。这个时候有10条用户信息,就需要调用接口读取图片10次,等10次接口调完,赋值再展示太慢了(例如下面的动图),这时候就需要懒加载了。

 

以下是上面动图的关键代码,下面的优化将在此基础上进行修改。

子组件部分(内层加载出来的卡片):

用户信息通过doctorData数组传进来,循环进行展示。

<template> 
  <div class="cons-doctor"  v-for="(item,index) in doctorData" :key="index">
     <div class="avatar">
        <img v-if="item.userPhoto" class="itemImg"  :src="item.userPhoto">
           <!--没有图片默认的图片 -->
        <img v-else src="~@/assets/images/doctor_lg.png" />
     </div>
     <div class="info">
        <p>
           <span class="txt"> 姓名:{{item.userName}}</span>
        </p>
            ...
     </div>
  </div> 
</template>
<script>
export default {
   props:{
      doctorData: {
        type: Array,
        default: []
      },
   }
}
</script>



父组件部分(包含用户信息的那部分框框):

这部分主要是获取到用户信息,例如[{userName: "哲学家", userPhoto: "photo\2021-03-02\7b48de3b-8e9c-4500-80a3-31d489567d55.jpg"}],把所有用户信息里面的userPhoto转为base64,再赋值给doctorData。然后子组件拿到doctorData,渲染出一个个用户信息卡片。

<template>
  <div>
    ...
    <doctor-wrap :doctorData="doctorData"/></doctor-wrap>
    ...
  </div
</template>

<script>
import doctorWrap from "@/components/consultant/doctorWrap"
import {getUserPages, getFileRead} from "@/api/api.js";

export default {
  name: 'index',
  components: {
    doctorWrap,
  },
  data() {
    return {
      doctorData: [], //医生列表数据
      totalCount: 0,
      pageSize: 10,
      currentPage: 1,
      querylist:{
        hospital:''
      },
      dataLoading: false,
    }
  },
  methods:{
    //获取用户信息
    getUserInfo(){
      let data = {
        hosptalCode: this.querylist.hospital,
        pageSize: this.pageSize, //页面大小
        pageNumber: this.currentPage, //页码
      }
      this.dataLoading = true
        // 调获取用户信息接口
       getUserPages(data).then(res=>{
         this.dataLoading = false
        if(res && res.code == 10000){
          this.totalCount = res.content.totalCount
          //对获取到的用户信息进行图片处理
          this.getImgDataList(res.content.list).then(data=>{
            //获取到处理后的数据  
            this.doctorData = data 
          })
        }
      })
    },
    // 获取图片加载后的数据
    getImgDataList(dataArr){
      return new Promise(async resolve=>{
        let _dataArr = [...dataArr]
        if(_dataArr.length===0){
          resolve(_dataArr)
        }
        let newDataArr = []
        for(let i = 0; i < _dataArr.length; i++){
          let tempObj = {..._dataArr[i]}
          if(!_dataArr[i].userPhoto){
            tempObj.userPhoto = ''
          }else{
            //获取base64
            tempObj.userPhoto = await this.getImgConverted(_dataArr[i].userPhoto)
          }
          newDataArr.push(tempObj)
        }
        resolve(newDataArr)
      })
    },
    //调接口将图片信息转为base64
    getImgConverted(fileUrl){
      return new Promise(async (resolve) => {
        let base64Url = ''
        await getFileRead(fileUrl).then(res => {
          base64Url = res
        });
        resolve(base64Url)
      })
    },
  }
}
</script>

三、懒加载思路和实现

上述的代码如上图所示,白屏时间过长。用户信息已经获取,还要等所有头像数据加载好,再一起展示在页面上。现在只有10条,如果有更多数据怎么办?

能不能等先设置一个默认的头像,让用户信息跟默认头像一起显示出来,然后头像加载完以后,再重新渲染一遍头像?可以!

这样就进入了优化的步骤一:

由于上面的子组件对图片进行判断的时候写的是userPhoto存在就显示图片,不存在就显示默认图片。那我们调用完用户信息接口的时候,直接给userPhoto都赋值空字符,让其显示默认图片,然后先把这个数据赋值给doctorData。这样界面就会先显示默认的图片。在调用完图片获取接口以后再赋值一次doctorData。这样界面就把有图片的数据渲染出来了。

这部分需要改动的代码(在上面代码的基础上):

    //获取用户信息
    getUserInfo(){
      let data = {
        hosptalCode: this.querylist.hospital,
        pageSize: this.pageSize, //页面大小
        pageNumber: this.currentPage, //页码
      }
      this.dataLoading = true
       getUserPages(data).then(res=>{
         this.dataLoading = false
        if(res && res.code == 10000){
          this.totalCount = res.content.totalCount

         /**这部分是新增代码**/
          let _res = JSON.parse(JSON.stringify(res.content.list))
          let defaultData = _res.map(item => {
            item.userPhoto =''
            return item
          })
          // 先赋值一次
          this.doctorData = defaultData
          /**这部分是新增代码**/

          //对获取到的用户信息进行图片处理
          this.getImgDataList(res.content.list).then(data=>{
            //获取到处理后的数据  
            this.doctorData = data 
          })
        }
      })
    },

效果如下图。

 

上述代码的修改,用户信息加载完以后就能立刻显示在页面上了,已经能解决页面白屏时间过长的问题了。但是,能不能再优化一下,让页面获取到一个图片就加载一个图片,而不是等所有图片加载出来一起替换默认图片?当然可以。

这样就进入了优化的步骤二:

页面怎么显示,归根结底就是要对doctorData动手脚,所以只要在每次调用获取图片接口的时候改变doctorData相应索引位置的数据就行了!

这部分需要改动的代码(在上面修改代码的基础上):

    //获取用户信息
    getUserInfo(){
      let data = {
        hosptalCode: this.querylist.hospital,
        pageSize: this.pageSize, //页面大小
        pageNumber: this.currentPage, //页码
      }
      this.dataLoading = true
       getUserPages(data).then(res=>{
         this.dataLoading = false
        if(res && res.code == 10000){
          this.totalCount = res.content.totalCount
          let _res = JSON.parse(JSON.stringify(res.content.list))
          let defaultData = _res.map(item => {
            item.userPhoto =''
            return item
          })
          this.doctorData = defaultData
          //对获取到的用户信息进行图片处理
          this.getImgDataList(res.content.list).then(data=>{
            //获取到处理后的数据  
            // this.doctorData = data //此处注释
          })
        }
      })
    },
    // 获取图片加载后的数据
    getImgDataList(dataArr){
      return new Promise(async resolve=>{
        let _dataArr = [...dataArr]
        // if(_dataArr.length===0){ //此处注释
        //   resolve(_dataArr) //此处注释
        // } //此处注释
        // let newDataArr = [] //此处注释
        for(let i = 0; i < _dataArr.length; i++){
          // let tempObj = {..._dataArr[i]} //此处注释
          if(!_dataArr[i].userPhoto){
            // tempObj.userPhoto = '' //此处注释
            this.doctorData[i].userPhoto = '' //此处新增
          }else{
            //获取base64
            // tempObj.userPhoto = await this.getImgConverted(_dataArr[i].userPhoto) //此处注释
            this.doctorData[i].userPhoto = await this.getFileRead(_DataArr[i].userPhoto) //图片逐个加载 此处新增
          } 
          // newDataArr.push(tempObj) //此处注释
        }
        // resolve(newDataArr) //此处注释
      })
    },

最终效果如下图。

大功告成!

 

 

 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue项目可以进行以下几方面的优化: 1. 代码优化:合理使用Vue特性和语法糖,避免冗余代码和重复计算,减少不必要的渲染,提高性能。同时,可以使用Vue提供的异步组件和路由懒加载功能,减少首屏加载时间。 2. 图片优化:对图片进行压缩和懒加载,减小页面加载大小和提高加载速度。可以使用工具如`imagemin`来压缩图片,并使用Vue插件如`vue-lazyload`实现图片的懒加载。 3. 异步请求优化:合理利用缓存和分页加载,减少网络请求次数和数据传输量。可以使用浏览器缓存技术如`localStorage`和`sessionStorage`来缓存数据,以及使用分页加载技术来分批请求数据。 4. 组件优化:对于频繁使用的组件,可以进行性能优化。比如,在组件中使用`v-show`代替`v-if`,避免频繁地销毁和创建组件;使用虚拟列表技术来优化大量数据的展示;使用`slot`插槽来减少不必要的组件嵌套等。 5. 代码分割:对于大型项目,可以将代码拆分成多个小模块,按需加载,减少首屏加载时间。可以使用Webpack提供的代码分割功能或者使用动态导入语法来实现。 6. 优化打包体积:可以通过Webpack的配置来进行优化,如使用压缩工具如`UglifyJS`来压缩JS代码,使用`MiniCssExtractPlugin`来提取CSS,使用`gzip`压缩文件等。 7. 服务端渲染(SSR):对于需要SEO和更好的首屏加载体验的项目,可以考虑使用Vue的服务端渲染技术来提高性能。 总之,Vue项目的优化需要综合考虑各个方面的因素,包括代码、图片、请求、组件、打包等,根据具体项目需求来选择相应的优化策略。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值