最近遇到的一个优化问题,记录一下。
场景: uniapp使用swiper渲染数据,只有三个swiper-item,目前是每次滑动都会去请求新的数据重新渲染当前item,卡顿很明显,需做优化;初始数据加载当前以及前后相邻两个数据,左滑或者右滑后,加载对应最新的一个数据,如果往回滑动,判断数据是否已经加载过,不再进行请求。
示例:
数据列表id:[1,2,3,4,5,6,7,8,9]
对应请求数据详细列表:[a,b,c,d,e,f,g,h,i]
我从数据列表单击某一个数据携带id进入到数据详情页面,当前做法为进入页面请求对应id的详细信息,再拿详细信息去请求对应的md文件进行页面的渲染,每次滑动都需要重新进行请求获取,造成页面会有明显的卡顿,体验不好,对这种情况进行一个优化。
思路:
1、首次进入页面后,初始化请求三个数据,将数据对应渲染到swiper-item上,滑动的时候,请求当前数据的下一个数据,并插入缓存数组,根据swiper当前最新的索引,更新swiper-item上对应的数据。还需要考虑数据小于3的情况。
1示例:进入 id为4的详情,初始化请求3,4,5的数据并缓存,并将3,4,5数据对应绑定到swiper-item 0,1,2上,默认显示为数据4页面,swiper索引为1,左滑到0,也就是数据3,进行请求数据2并插入缓存数组前面,右滑同理,并将 swiper-item上的数据替换为对应的 2,4 达到正常的效果,最后就是要考虑边界的问题,从头滑到尾 以及从尾滑到头的位置计算。
//对应三个swiper-item的数据
let article0 = null;
let article1 = null;
let article2 = null;
//数据缓存数组
let cacheData = [];
//获取3个初始化数据
const initData = async () => {
try{
//进入4详情,计算相邻id,此时应该初始化[3,4,5]
const useIdArr = caleFileId();
const filePromises = [], mdPromises = [];
useIdArr.forEach(item => {
filePromises.push(fetchFile({id:item.id}))
})
const fileResults = await Promise.all(filePromises)
fileResults.forEach(item => {
mdPromises.push(fetchMd(item))
})
const mdResults = await Promise.all(mdPromises)
cacheData = [...mdResults]
}catch(err){
console.log(err)
}
}
//记录上一次位置
let oldCurrent = 0
//滑动方向
let direction = null
//swiper滑动监听, 以id 4 进入为例
const changeSwiper = async (e) => {
const { current } = e.detail;
if(current - oldCurrent == 2 || current - oldCurrent == -1) {
//第一次左滑,获取id为2,再次滑动则为1,后续同理,需考虑边界
direction = 'left'
}else if(current - oldCurrent == 1 || current - oldCurrent == -2) {
//第一次右滑,获取id为6,再次滑动为7,后续同理,需考虑边界
direction = 'right'
}
//保存滑动位置记录
oldCurrent = current;
// id由上面滑动计算得到,进行请求
fetchFile(id)
}
//文件请求
const getFile = async (id) => {
//是否已做请求,存在缓存,拿缓存数据
if(useIdArr.value.indexOf(id) > -1){
caleDataLocation()
return
}
const fileData = await fetchFile({id})
const mdResult = await fetchMd(fileData)
//加入缓存
if(direction === 'left'){
useIdArr.unshift(mdResult)
}else{
useIdArr.push(mdResult)
}
//进行swiper-item数据的替换
caleDataLocation(id)
}
//进行计算当前对应swiper-item的数据
const caleDataLocation = (id) => {
//根据direction方向、oldCurrent的位置,以及当前id在缓存中的位置计算替换前后两个item的数据
}
以上就是主要的实现方法,最后的结果可以达到预期效果;
有尝试过以动态的形态去实现,但是发现仍有问题,最后采用了这种办法;
大家有什么问题或者更好的想法欢迎讨论。