项目场景:
在开发壁纸小程序的时候遇到这样一个场景,通过壁纸缩略图页面跳转至壁纸大图页面,需要一次载入的图片太多,这样就需要swiper里需要很多swiper-item,如此一来渲染的时候就会很消耗性能和网络带宽,渲染时会有一大段的空白时间,有时还会造成卡顿,体验非常差。
问题描述
classlist.vue是壁纸缩略图页面,preview.vue是壁纸大图页面。
点击缩略图进行跳转时进行传参,参数为图片的id,使用onLoad接收参数,通过findIndex()方法获取图片的索引currentIndex,通过swiperChange()方法修改currentIndex的值。
由于缩略图不大,classList是请求后得到的图片对象数组,一次请求12张,将数据继续追加至classList,缩略图与大图的url可以通过修改后缀名实现,所以使用localStorage维护classList。若用户在缩略图页面多次下拉刷新后(如下拉5次,则60张图),后续请求点击预览大图时,则会一次性请求对应数量(60张)的大图,如下图所示。
解决方案:
图片预加载,思路是利用v-if控制图像的渲染,维护一个已看数组readImgs,通过判断readImgs是否包含当前图片的index来请求渲染大图。
1.初始化readImgs,将当前索引、前一项和后一项追加进数组。
2.当向右滑动时,接着为readImgs的下一项赋值;当向左滑动时,接着为readImgs的前一项赋值(应注意索引边界和数组去重)。
HTML如下:
<swiper circular :current="currentIndex" @change="swiperChange">
<swiper-item v-for="(item,index) in classList" :key="item._id">
<image v-if="readImgs.includes(index)" :src="item.picurl" mode="aspectFill"></image>
</swiper-item>
</swiper>
JS如下:
const currentIndex = ref(0)
const readImgs = ref([])
// 获取storageClassList
const storageClassList = uni.getStorageSync("storageClassList") || []
classList.value = storageClassList.map(item => {
return {
...item,
picurl: item.smallPicurl.replace("_small.webp", ".jpg")
}
})
// 获取传来的参数,并且通过findIndex找到图片的索引
onLoad((e) => {
currentId.value = e.id
currentIndex.value = classList.value.findIndex(item => item._id == currentId.value)
readImgsFun()
})
// swiper滑动事件,修改图片索引
const swiperChange = (e) => {
currentIndex.value = e.detail.current
readImgsFun()
}
// 已读数组边界处理、去重
const readImgsFun = () => {
readImgs.value.push(
currentIndex.value <= 0 ? classList.value.length - 1 : currentIndex.valu - 1,
currentIndex.value,
currentIndex.value >= classList.value.length - 1 ? 0 : currentIndex.value + 1)
readImgs.value = [...new Set(readImgs.value)]
}
记录一下自己的思考,如果有更好的方法,欢迎大家友好讨论!