小程序---懒加载

因为列表页的图片太多,导致性能降低,所以决定用懒加载优化一下。所谓懒加载,就是图片没有显示的时候用占位图,等到显示的时候,将展位图改成真正要展示的图片。

一、onPageScroll(监听页面滚动)

提到懒加载,第一个想到的当然是onPageScroll啦。
首先,选一张占位图,并且在data中声明一下图片的高度和一个跟列表长度一样的false数组(这边为什么全部是false?因为要让图片全部先用占位图占着,等到显示的时候改为true)。

data: {
        damoHeight :'110',
        arry:[false,false,false,false,false,false]
    },

然后在onload中处理首屏要转为true的图片,并进行渲染。

onLoad: function () {
	let self = this;
	swan.getSystemInfo({
	   success: res => {
	       let windowHeight = res.windowHeight;//获取屏幕的高度
	   }
	});
	//num是首屏要渲染的数量
	let num = Math.ceil(windowHeight / self.data.damoHeight);// self.data.damoHeight为data中图片的高度
	self.data.num = num;
    for(let i = 0; i < num; i++){
         self.data.arry[i] = true;//将要渲染的几张图片在数组里改为true
     };
     //将得到的新数组渲染到页面
     self.setData({
         arry:self.data.arry
     });
}

接着在onPageScroll方法中监听scrollTop(滚动顶端的值即滚动的像素),计算有几张图片的状态要改为true,从而实现想要的效果。

onPageScroll: function (res){
        let self = this;
        let str = parseInt(res.scrollTop / self.data.damoHeight);// self.data.damoHeight为data中图片的高度
        that.data.arry[self.data.num+str] = true;//这边的序号要加上之前已经显示的数量
         //将得到的新数组渲染到页面
        that.setData({
            arry:that.data.arry
        })
},

界面布局

<image src="{{arry[index] ? catagory.img : '/images/loading.gif'}}" ></image>

效果是实现了,但是页面列表的数据会根据不同条件的选择,列表的数量是不固定的,所以我们没有办法先写死false数组。然后我在下拉的过程中,发现数组的长度会自动往后加。本以为大功告成了,但是有一个bug,就是当我下拉的速度非常快的时候,会有一些位置没有补true,例:在这里插入图片描述
查了资料才知道,因为onPageScroll方法是下拉监听函数,在下拉的过程中一直在执行,在这里面setData是非常耗性能的,所以把它做了延时。我们懒加载的目的就是优化性能,所以怎么能用耗性能的方法呢,我又找到了下面这种方法。

二、IntersectionObserver API

什么是IntersectionObserver?其实它就是创建了一个观察的视口,当你要观察的元素进入到这个视口,就可以对这个元素进行操作,这个是发异步的,所以不用考虑耗性能的问题啦。
这次的列表数据,每个图片都要加上show:false。举个栗子

let list = [
	{
		name:"aaaa",
		img:"aa.jpg",
		show:false
	},
	{
		name:"bbbb",
		img:"bb.jpg",
		show:false
	},
	{
		name:"cccc",
		img:"cc.jpg",
		show:false
	},
]

列表数据大概就是这个意思。因为我的列表是发异步的到的,后面选择不同的条件,得到的列表数据会改变,所以我在setData的回调函数里进行操作的。

success: function (res) {
   //数据获取成功后,先渲染一遍
   self.setData({
       list:res.data.list,
   },function(){
   	//如果已经存在这个观察窗口,停止监听
       if(self.intersectionObserver){
           self.intersectionObserver.disconnect();
       }
       //遍历得到的数组,对其进行操作
       for(let i in res.data.list){
      		//创建一个视口,观察多个元素
           self.intersectionObserver = swan.createIntersectionObserver(self,{
               observeAll: true,
           });
           //在视口里观察对应的元素,这边是.item0,.item1,.item2,.item3,...
           self.intersectionObserver.relativeToViewport().observe('.item-'+i, (ret) => {
               //ret.intersectionRatio > 0的意思是元素露出一点点
               if(ret.intersectionRatio > 0){
                   res.data.list[i].show = true;//将列表里对应个数的图片显示出来
               };
               //将得到的新数组渲染到页面
               self.setData({
                   list:res.data.list,
               });
           });
       }
   });
},

在页面退出后,要停止监听

onUnload: function() {
   // 监听页面卸载的生命周期函数
   let self = this;
   if(self.intersectionObserver){
       self.intersectionObserver.disconnect();
   }
},

界面布局

<view s-for="{{list}}" s-key="i" s-for-item="n" class="item-{{index}}">
    <view>
        <image src="{{n.show ? n.logo : '/images/loading.gif'}}"></image>
    </view>
</view>

这样做确实能实现效果,而且还不消耗性能。

问题来了
我页面中的list会根据条件的选择,获取到新的list进行刷新。第一次进入页面的时候完全没问题,然后在页面上选择了一个条件,得到一个新的list列表,但intersectionObserver观察到的不仅仅是这个新得的列表,还有我之前旧的列表。当我再选一个条件,intersectionObserver会观察3次的列表,而不是当前list。所以我怀疑是不是之前的视口没有关闭,一直在切换着观察,但我在创建之前已经把之前观察的窗口停止监听了self.intersectionObserver.disconnect();,打印出来看它的disconnect也是为true的。
我查了vue的intersectionObserver也是这么停止监听的,但在小程序里没有起到停止监听的作用,我不知道到问题出哪了,请看到这篇文章的大佬提点一下

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值