uniapp中懒加载图片组件的封装与应用


    在移动应用开发领域,图片资源的加载效率对用户体验有着至关重要的影响。过多图片同时加载不仅会消耗大量流量,还可能导致页面卡顿、加载缓慢。为解决这一问题,懒加载技术应运而生,它能让图片在即将进入可视区域时才开始加载,有效减轻页面初始加载压力。本文将基于uniapp框架,详细讲解如何封装一个功能强大的懒加载图片组件,并展示其在商品列表组件中的实际应用。

一、懒加载图片组件功能详解

    懒加载图片组件的设计围绕性能优化用户体验提升两大核心目标。性能层面,它通过精准的可视区域判断,实现图片的按需加载,避免在页面初始化阶段加载大量图片资源,从而降低服务器请求压力,提升页面响应速度;用户体验方面,组件支持丰富的过渡效果、加载失败提示以及多样化的占位图展示,确保在图片加载过程中,用户能获得流畅且直观的视觉体验。

  1. 初始化阶段:组件在创建时,会调用generateUUID函数生成一个全局唯一的ID(uid),用于在页面中唯一标识该组件实例。同时,绑定滚动事件监听,为后续的可视区域判断做准备。
  2. 可视区域判断:利用uni.createSelectorQuery方法,获取组件在页面中的位置信息(boundingClientRect)。该方法返回的结果包含组件的顶部坐标(top)等关键信息,通过将其与viewHeight进行比较,判断组件是否进入可视区域。当data.top - viewHeight < 0时,认为组件即将或已经进入可视区域,此时触发图片加载逻辑。
  3. 图片加载过程
    • 加载触发:若判断组件进入可视区域,且imageSrc不为空,则将loadImg设置为true,正式发起图片加载请求;若imageSrc为空,则将isLoadError设为true,视为加载失败。
    • 加载成功:当图片成功加载时,触发handleImgLoad方法,将showImg设置为true,使图片在页面中显示。同时,通过setTimeout延迟50毫秒后,将showTransition设为true,激活渐变过渡动画,让图片从低透明度逐渐清晰显示,提升视觉体验。
    • 加载失败:若图片加载过程中出现错误,触发handleImgError方法,将isLoadError设置为true,此时组件会显示加载失败的占位图,告知用户图片加载异常。
  4. 性能优化机制:为避免滚动事件频繁触发导致的性能问题,组件引入了throttle函数对滚动监听函数scrollFn进行防抖处理。throttle函数会限制scrollFn在一定时间间隔(200毫秒)内最多执行一次,减少不必要的计算,确保页面滚动流畅。

    核心实现代码如下:

// 防抖处理滚动事件(200ms触发一次)
scrollFn: throttle(function () {
  if (that.loadImg || that.isLoadError) return;
  const query = uni.createSelectorQuery().in(that);
  query.select('#' + that.uid).boundingClientRect(data => {
    // 当组件顶部距离可视区域顶部小于viewHeight时触发加载
    if (data.top - that.viewHeight < 0) {
      that.loadImg = !!that.imageSrc; // 非空地址才加载
      that.isLoadError =!that.loadImg; // 空地址视为加载失败
    }
  }).exec();
}, 200)

    首先,通过throttle函数对内部的匿名函数进行包装,实现每200毫秒最多执行一次的效果。在匿名函数内部,先判断loadImg(图片是否正在加载)和isLoadError(图片是否加载失败)的状态,若其中一个为true,则直接返回,不再进行后续的可视区域判断,避免重复操作。接着,使用uni.createSelectorQuery().in(that)创建一个选择器查询对象,并将其作用域限定在当前组件实例(that)内。通过query.select('#' + that.uid)选中当前组件(依据唯一ID),再调用boundingClientRect方法获取组件的位置和尺寸信息。当获取到的组件顶部坐标(data.top)与viewHeight的差值小于0时,表明组件进入可视区域,此时根据imageSrc是否为空,分别设置loadImgisLoadError的值,决定是否触发图片加载。
    为了让加载更加流畅,补充动画效果:

/* 初始状态:低透明度 */
image.origin-img {
  opacity: 0.3;
  transition: opacity 0.5s; /* 渐变过渡 */
}

/* 加载完成:高透明度 */
image.origin-img.show-transition {
  opacity: 1;
}

    在CSS样式中,.origin-img类对应组件中的图片元素。初始状态下,为其设置opacity: 0.3,使图片呈现低透明度的模糊状态;同时,添加transition: opacity 0.5s属性,定义当opacity属性发生变化时,以0.5秒的时长进行平滑过渡。当图片加载完成,showTransition变为true,此时图片元素会添加.show-transition类,该类将opacity设置为1,触发过渡动画,使图片从模糊逐渐变得清晰。
    由于一开始图片可能在加载过程中,需要插入占位图撑起组件高度,避免出现“塌陷”:

/* 加载中:动态灰色渐变 */
.looming-gray {
  animation: looming-gray 1s infinite linear;
  background-color: #e3e3e3;
}

/* 加载失败:错误图标 */
.loadfail-img {
  background: url('~@/static/easy-loadimage/loadfail.png') no-repeat center;
  background-size: 50%;
}

    对于loadingMode为“looming - gray”时的占位图样式,.looming-gray类通过animation: looming-gray 1s infinite linear属性,应用名为looming-gray的动画。该动画会使元素的背景颜色在1秒内,以线性方式无限循环地在#e3e3e3aa#e3e3e3之间变化,从而实现动态灰色渐变效果,直观地展示图片加载中的状态。而当图片加载失败时,对应的.loadfail-img类会设置背景为指定路径(~@/static/easy-loadimage/loadfail.png)的错误图标,图标居中显示且大小为容器的50%,清晰地提示用户图片加载出现问题。

二、在商品列表组件中的应用

(1)引入组件

// 在promotionList组件中注册
import easyLoadimage from '@/components/easy-loadimage/easy-loadimage.vue'
export default {
  components: { easyLoadimage }
}

    在商品列表组件(promotionList)的<script>标签内,通过import语句从指定路径引入easy-loadimage组件。然后,在组件的components选项中进行注册,将easyLoadimage组件名称与实际组件实例关联起来,这样在模板中就可以像使用内置组件一样使用该懒加载图片组件。

(2)模板中使用

<view class="item" v-for="(item, index) in list" :key="index">
  <view>
    <!-- 懒加载图片组件 -->
    <easy-loadimage 
      mode="widthFix" 
      :image-src="item.coverImage" 
      loading-mode="skeleton-1"
    ></easy-loadimage>
  </view>
  <!-- 商品信息 -->
  <view class="text-info">
    <view class="title line2">{{ item.productName }}</view>
    <view class="sale-volume">特产属地:{{ item.originProvince }}</view>
    <view class="price">{{ $t(`¥`) }}{{ item.price }}</view>
  </view>
</view>

    在商品列表的模板中,通过v-for指令遍历list数组,为每个商品项渲染对应的界面。在每个商品项内部,使用<easy-loadimage>标签插入懒加载图片组件。其中,mode="widthFix"设置图片的显示模式,使图片宽度自适应容器,同时保持原始宽高比;:image-src="item.coverImage"通过动态绑定的方式,将每个商品的封面图片地址(item.coverImage)传递给组件,确保组件加载正确的图片资源;loading-mode="skeleton-1"指定图片加载过程中显示“skeleton - 1”样式的骨架屏占位图,在图片未加载完成时,以动态光影效果模拟图片形状,提升用户等待时的视觉体验。
在这里插入图片描述

三、配合分页加载丝滑展示图片

    分页加载与懒加载是提升长列表性能的两大核心技术。本方案通过协同二者,实现了商品数据的分批请求与图片的按需加载,确保页面流畅运行。

  1. 分页参数管理:通过pageNumpageSize控制数据请求量,初始加载第1页10条数据
  2. 触底加载机制:监听onReachBottom事件,当滚动到页面底部时自动加载下一页
  3. 数据合并策略:新数据通过concat追加到原列表,避免整体刷新导致的视觉抖动
  4. 加载状态控制:通过loadend标记判断是否还有更多数据,控制加载提示文案

    核心代码如下:

// 数据结构与分页参数
data() {
  return {
    pageNum: 1,
    pageSize: 10,
    goodsList: [],
    loadend: false
  }
},

// 分页加载方法
getList() {
  getProductList({ pageNum: this.pageNum, pageSize: this.pageSize })
    .then(({ records, pages }) => {
      this.goodsList = this.goodsList.concat(records); // 合并新数据
      this.loadend = pages <= this.pageNum; // 判断是否加载完毕
      this.pageNum++; // 页码递增
    });
},

// 触底事件监听
onReachBottom() {
  if (!this.loadend) this.getList();
}

    当新一批商品数据加载完成后,列表组件会渲染包含懒加载图片的新条目:

<!-- 商品列表中使用懒加载图片 -->
<promotionList :list="goodsList">
  <easy-loadimage 
    :image-src="item.coverImage" 
    loading-mode="skeleton-1"
  ></easy-loadimage>
</promotionList>

    懒加载组件会自动监听这些新渲染的图片元素,当它们进入可视区域时触发加载,确保无论数据分多少页加载,图片始终按需加载。通过这种组合方案,页面在加载大量商品图片时,既能保证数据的有序加载,又能优化图片资源的使用效率,实现流畅的用户体验。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jerry说前后端

请作者喝杯冰阔落~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值