当前位置: 首页 > web >正文

小程序开发:懒加载只加载当前和滑动到的图片

        小程序图片预览优化:只加载当前和滑动到的图片

        在做小程序开发时,我们经常会遇到这样的场景: 点击图片列表中的某一张,跳转到预览页面,通过 swiper 组件实现图片轮播预览。

        一个常见的问题是: 如果一次性传了一整个图片数组,swiper-item 中每个 image 都会去加载网络资源,导致首屏渲染慢流量浪费

        那么有没有办法优化,只加载当前需要看的那几张图片呢?

1.思路分析

         1.入口页传递 ID 点击列表图片时传递当前图片的 _id 给预览页。预览页接收 IDonLoad 中通过传入的 id 去缓存的 classList 找到对应图片的下标 index

        2.定义一个已读数组 用一个 ref([]) 存储需要加载的图片索引,比如 readImg

        3.初始化加载 首次进入时,把传入的图片下标 index 推入 readImg,这样只会加载这一张。

        4.监听轮播变化 swiper@change 事件触发时,获取新的下标 current,再推入 readImg

        条件渲染 在模板中,image 标签通过 v-if="readImg.includes(index)" 判断,只加载出现在数组里的图片。

        这样就能保证:

                👉 进入时只加载当前图片

                👉 滑动到哪一张再加载哪一张

                👉 大幅减少首屏加载压力

2.代码实现

<navigator :url="/pages/preview/preview?id=${item._id}" class="item" v-for="item in classList" :key="item._id"><image :src="item.smallPicurl" mode="aspectFill"></image>
</navigator>

        首先跳转的时候传递item.id用来筛选当前index。效果图

        通过id去进行逻辑判断。

<template><view class="preview" v-if="currentInfo"><swiper circular :current="currentIndex" @change="swiperChange" ><swiper-item v-for="(item,index) in classList" :key="item._id"><image v-if="readImg.includes(index)" @click="maskChange" :src="item.picUrl" mode="aspectFill"></image></swiper-item></swiper><view class="mask" v-if="maskState"><view class="goBack" :style="{top:getStatusBarHeight()+'px'}" @click="goBack"><uni-icons type="back" color="#fff" size="20"></uni-icons></view><view class="count">{{currentIndex+1}} / {{classList.length}}</view><view class="time"><uni-dateformat :date="new Date()" format="hh:mm"></uni-dateformat></view><view class="date"><!-- 一般用法 --><uni-dateformat :date="new Date()" format="MM月dd月"></uni-dateformat></view><view class="footer" v-if="currentInfo"><view class="box" @click="clickInfo"><uni-icons type="info" size="28"></uni-icons><view class="text">信息</view></view><view class="box" @click="clickScore"><uni-icons type="star" size="28"></uni-icons><view class="text">{{currentInfo.score}}分</view></view><view class="box" @click="clickDownload"><uni-icons type="download" size="28"></uni-icons><view class="text">下载</view></view></view></view><uni-popup ref="infoPopup" type="bottom"><view class="infoPopup"><view class="popHeader"><view class=""></view><view class="title">壁纸信息</view><view class="close" @click="clickInfoClose"><uni-icons type="closeempty" size="18" color="#999"></uni-icons></view></view><scroll-view scroll-y><view class="content" v-if="currentInfo"><view class="row"><view class="label">壁纸ID:</view><text user-select class="value">{{currentInfo._id}}</text></view><view class="row"><view class="label">分类:</view><text selectable class="value class">图片</text></view><view class="row"><view class="label">发布者:</view><text selectable class="value">{{currentInfo.nickname}}</text></view><view class="row"><view class="label">评分:</view><view class="value roteBox"><uni-rate readonly :value="currentInfo.score" size="16" touchable /><text class="score">{{currentInfo.score}}</text></view></view><view class="row"><view class="label">摘要:</view><view class="value">{{currentInfo.description}}</view></view><view class="row"><view class="label">标签:</view><view class="value tabs"><view class="tab" v-for="item in currentInfo.tabs " :key="item">{{item}}</view></view></view></view></scroll-view></view></uni-popup><uni-popup ref="scorePopup" :is-mask-click="false"><view class="scorePopup"><view class="popHeader"><view class=""></view><view class="title">{{isScore?"评分过了":"评分壁纸"}}</view><view class="close" @click="clickScoreClose"><uni-icons type="closeempty" size="18" color="#999"></uni-icons></view></view><view class="content"><uni-rate v-model="userScore" allowHalf :disabled="isScore" disabled-color="#FFCA3E" /><text class="text">{{userScore}}分</text></view><view class="footer"><button @click="submitScore" :disabled="!userScore || isScore" type="default" size="mini"plain>确认评分</button></view></view></uni-popup></view>
</template>
<script setup>import {ref} from 'vue';import {onLoad} from '@dcloudio/uni-app'import {getStatusBarHeight} from '@/utils/system';import {apiGetSetupScore,apiWriteDownload,apiDetailWall} from '@/api/apis.js'import {onShareAppMessage,onShareTimeline} from '@dcloudio/uni-app'const readImg = ref([])const currentId = ref(null)const classList = ref([])const isScore = ref(false)const storgClassList = uni.getStorageSync("storgClassList") || []classList.value = storgClassList.map(item => {return {...item,picUrl: item.smallPicurl.replace("_small.webp", ".jpg")}})console.log(classList.value);const maskState = ref(true)const infoPopup = ref(null)const scorePopup = ref(null)const userScore = ref(0)const currentIndex = ref(0)const currentInfo = ref({})//接收路径参数onLoad(async(e) => {console.log(e);currentId.value = e.idif(e.type==='share'){let res =await apiDetailWall({id:currentId.value})classList.value=res.data.map((item)=>{return{...item,picUrl: item.smallPicurl.replace("_small.webp", ".jpg")}})}currentIndex.value = classList.value.findIndex(item => {return item._id === currentId.value})currentInfo.value = classList.value[currentIndex.value]readImg.value.push(currentIndex.value)})//滑动修改索引值const swiperChange = (e) => {currentIndex.value = e.detail.currentreadImg.value.push(currentIndex.value)currentInfo.value = classList.value[currentIndex.value]}//点击打开评分弹窗const clickScore = () => {if (currentInfo.value.userScore) {isScore.value = trueuserScore.value = currentInfo.value.userScore}scorePopup.value.open()}//关闭评分窗const clickScoreClose = () => {scorePopup.value.close()userScore.value = 0isScore.value = false}//点击关闭弹窗const clickInfoClose = () => {infoPopup.value.close()}//点击触发info弹窗const clickInfo = () => {infoPopup.value.open()}//遮罩层打开关闭控制const maskChange = () => {maskState.value = !maskState.value}//确认评分const submitScore = async () => {let {classid,_id: wallId} = currentInfo.valuelet res = await apiGetSetupScore({classid,wallId,userScore: userScore.value})if (res.errCode === 0) {uni.showToast({title: "打分成功"})}classList.value[currentIndex.value].userScore = userScore.valueuni.setStorageSync("storgClassList", classList.value)scorePopup.value.close()}//返回上一页const goBack = () => {uni.navigateBack()}//点击下载const clickDownload = async () => {// #ifdef H5uni.showModal({content: "请长按保存壁纸",showCancel: false})// #endif// #ifndef H5try {uni.showLoading({title: "下载中..",mask: true})let {classid,_id: wallId} = currentInfo.valuelet res = await apiWriteDownload({classid,wallId})if (res.errCode !== 0) {throw res}uni.getImageInfo({src: currentInfo.value.picUrl,success: (res) => {uni.saveImageToPhotosAlbum({filePath: res.path,success: (res) => {uni.showToast({title: "保存成功,到相册查看",icon: "none"})},fail: (err) => {if (err.errMsg === 'saveImageToPhotosAlbum:fail cancel') {uni.showToast({title: "保存失败,请重新下载",icon: "none"})return}uni.showModal({title: "授权提示",content: "需要授权保存相册",success: (res) => {if (res.confirm) {uni.openSetting({success: (setting) => {if (setting.authSetting['scope.writePhotosAlbum']) {uni.showToast({title: "获取授权成功",icon: 'none'})} else {uni.showToast({title: "获取授权失败",icon: 'none'})}}})}}})},complete: () => {uni.hideLoading()}})}})} catch (err) {uni.hideLoading()}// #endif}//分享给好友onShareAppMessage((e)=>{return {title:"壁纸wallpaper",path:"/pages/preview/preview?id="+currentId.value+"&type=share"}})//分享给朋友圈onShareTimeline(()=>{return {title:"壁纸wallpaper",query:"id="+currentId.value}})
</script>

        首先通过id去筛选当前index,那么我们就可以通过下标获取到缓存中的图片列表中的我们当前预览的图片,轮播图动态改变下标也会改变currentIndex,这样就可以实现我们的预览图片效果,懒加载我们只希望加载预览过的图片,那么我们可以给image设置渲染条件 index===currintIndex但是这样我们滑动会有空白,而且浏览过的还是空白,我们用一个数组不管是滑动还是第一次点击预览都会把indexpush进去,那么在展示渲染的时候v-if只需要数组includes包含当前index就可以了。

http://www.xdnf.cn/news/19704.html

相关文章:

  • 【Doris入门】Doris数据表模型:主键模型(Unique Key Model)详解
  • 【重学MySQL】九十六、MySQL SQL Mode高效配置全攻略
  • Linux 孤儿进程 (Orphan Process)
  • 【学Python自动化】 6.1 Python 模块系统学习笔记 (与 Rust 对照)
  • Linux中命令收集
  • UE5 C++ 第三方动态库的使用
  • 「任天堂物语」08 任天堂的山寨时代
  • 递归进阶之全排列、组合
  • JS箭头函数
  • 数字铁流:2025.9.3国庆大阅兵系统架构解析
  • 贪心算法解决固定长度区间覆盖问题:最少区间数计算
  • OpenCV 实战:图像模板匹配与旋转处理实现教程
  • G156HAN04.0 宽温域高亮工业屏技术白皮书
  • Spring Ioc —— 集合类型的依赖注入
  • Next.js渲染模式:SSR、SSG与ISR揭秘
  • 第六章:健壮Go应用:工程实践与生产就绪之测试
  • 旧实例数据库损坏sqlserver启动失败解决办法
  • Java PDF转多种图片格式:技术实践与性能优化
  • CS25FTFR010 1225 0.01R/10mR有哪些优势-华年商城
  • 联邦学习论文分享:Federated Learning via Synthetic Data
  • 搭建APP应用程序如何选择服务器
  • 选择图片转base64格式组件简单封装-Base64ImageInpu
  • 【Node.js教程】Express框架入门:从搭建到动态渲染商品列表
  • 埃文科技亮相2025中部数字经济产业发展大会暨数智创新博览会
  • 数据库事务隔离级别与 MVCC 机制详解
  • MiniCPM-V 4.5实战,实现图片、视频、多图的推理
  • 如何使用 JMeter 进行接口测试。
  • 设计模式-状态模式 Java
  • 盲盒小程序系统开发:构建盲盒社交新生态
  • api验签