Bootstrap

微信小程序之使用上拉加载实现图片懒加载

在微信小程序中,有2个事件,相信大家都很熟悉
下拉重新加载
上拉加载更多
事件是这么个事件,至于事件触发后干嘛,那就看代码了
首先要在对应得地方xxxxpage.json打开这个

  "onReachBottomDistance": 100

至于这个值100还是多少要看你的实际情况,为了不让用户看到默认的框框啥的,应该是设置大一些!
xxxpage.js中

  onReachBottom(){
  //组件的class="lazyimage"
    var child =this.selectComponent('.lazyimage');
    if(child){
      child.onScrollIndex();//告知懒加载组件,触发了上拉触底事件
    }else{
      console.log(this);
    }
  }

然后就是我们的组件代码了 比如命名为lazyimage
lazyimage.js

// components/goodsParse/goodsParse.js
Component({

  /**
   * 组件的属性列表
   */
  properties: {
    parseData: {
      type: Array,
      value: []
    },
    param: {
      type: String
    },
    scrollindex:{
      type:Number,
      value:0,
      default:0
    },
    lazyload:{
      type:Boolean,
      value:false
    }
  },

  /**
   * 组件的初始数据
   */
  data: {
    imageCount: 0,
    imagedatas:[],
    loadcount:0,
    current_load_height:0,//本次渲染的图片的总高度 如果本次渲染的总高度不足1500 则会再次渲染per_load_count
    current_loaded_ok:false,//本次是否渲染完成
    per_load_min_height:1500,//每次至少渲染多少高度
    per_load_count:3//每次渲染的张数,如果渲染的总高度不足,会继续渲染
  },

  /**
   * 组件的方法列表
   */
  methods: {
    handleImgtap() {

    },
    onImageLoad(e) {
      this.data.imageCount ++
      //又不用渲染UI 所以下面的代码没必要
      // this.setData({
      //   imageCount: this.data.imageCount
      // })

      if(e.detail){
        if(e.detail.height){
          //本张图片渲染的高度
          this.data.current_load_height+=e.detail.height;
        }
      }

      if(this.data.lazyload){
      //本次懒加载的图片已经加载完成了
      if(this.data.imageCount == this.data.loadcount){
        this.data.current_loaded_ok=true;
         this.triggerEvent('onImageLoad', this.data.imageCount);

         //未完待续 如果还可以继续加载,如果刚刚加载的总高度小于屏幕的总高度,则继续贪婪加载
         if(this.data.current_load_height<this.data.per_load_min_height){
           //本次渲染的高度太小了,看看是否可以继续渲染,再次渲染3张
           this.loadNext(this.data.per_load_count);
         }
      }
      }else{
        //非懒加载
        if(this.data.imageCount == this.data.imagedatas.length){
          this.triggerEvent('onImageLoad', this.data.imageCount);
        }
      }


      //如果渲染不够,还可以继续渲染
      // console.log(e);//可以通过e来计算本次加载是否足够,不够的话补足剩余的数量
    },
    loadNext(num){
      if(this.data.loadcount<this.data.imagedatas.length){
        //渲染接下来的N个?
        var _max = this.data.imagedatas.length;
        if(this.data.loadcount<(_max)){
          this.data.current_load_height=0;
          var _temptop = Math.min(this.data.loadcount+num,(_max));
          // console.log('loadcount',this.data.loadcount,'images',this.data.imagedatas.length,'temp',_temptop);
          if(_temptop>this.data.loadcount){
            var _new_array=new Array();
            var _datas =this.data.imagedatas;
            for(var k=this.data.loadcount;k<_temptop;k++){
              if(this.data.imagedatas.length>k){
                _new_array.push(
                  {
                    vkey:'imagedatas['+k+'].src',
                    src:_datas[k].presrc
                  }
                );
              }
            }
            if(_new_array.length>0){
              var _obj={};
              for(var ii of _new_array){
                _obj[ii.vkey]=ii.src
              }
              this.setData(_obj);
              // console.log('set new images src!');
            }
            this.data.loadcount = _temptop;
          }
        }
      }
    },
    onScrollIndex(){
      //这个函数是给外部调用的,一般发生在上拉触底(要基于实际去设定这个高度值)的时候
      if(this.data.imagedatas.length ==this.data.loadcount){
        // console.log('已经全部完成渲染,无法继续执行更多的懒加载');
        //已经全部懒加载完成,不需要继续加载了
        return;
      }
      if(!this.data.current_loaded_ok){
        // console.log('上一次的渲染未完成··· ·· ·');
        return;
      }
      // console.log('parent`s scroll-view scroll to lower!');
      if(this.data.imageCount<this.data.loadcount){
        // console.log('之前加载的图片还未完全加载完成');
        return;
      }
      this.loadNext(this.data.per_load_count);
    },
    requireLoadAll(){
      //父级页面要求加载全部
      if(this.data.loadcount != this.data.imagedatas.length){
        var _n = this.data.imagedatas.length-this.data.loadcount;
        if(_n>0){
          if(!this.data.current_loaded_ok){
            // console.log('上一次的渲染未完成··· ·· ·');
            return;
          }
          // console.log('parent`s scroll-view scroll to lower!');
          if(this.data.imageCount<this.data.loadcount){
            // console.log('之前加载的图片还未完全加载完成');
            return;
          }
          this.loadNext(_n);
        }
      }
    }
  },
  attached(){
    // console.log('load goods-parse attached!');
    var _lazyload=this.data.lazyload;
    if(this.data.parseData!=null && this.data.parseData.length>0){
      var _imgarray=new Array();
      var _i =0;
      for(var img of this.data.parseData){
        _i ++;
        if(_i<= this.data.per_load_count || !_lazyload){
        _imgarray.push({
          src:img,
          presrc:img
        });
      }else{
        _imgarray.push({
          src:null,
          presrc:img
        });
      }

      }
      this.data.loadcount =this.data.per_load_count;//当前有渲染的序号
      this.setData({
        imagedatas:_imgarray
      });
      console.log(_imgarray);
    }
  }
})

对应的lazyimage.wxml代码如下(这个看你的实际情况修改)

<view class="parse_box">
    <block >
        <view class="u-padding-top-10" style="font-size:0px;">
            <block wx:if="{{parseData}}">
                <view>
                    <block wx:for="{{imagedatas}}" wx:for-item="item" wx:for-index="index" wx:key="index">
                        <block wx:if="{{item.src}}">
                            <image class="parse_image" src="{{item.src}}" mode="widthFix" bindload="onImageLoad" binderror="onImageLoad"/>
                        </block>
                    </block>
                </view>
            </block>
        </view>
    </block>
</view>

至于样式就不贴了!
这个组件适用于单图横向100vw的模式,比如商品的图片列表纵向显示
关键点在于
图片数据是parseData
比如:
[“https://xxx.jpg”,“https://xxx.jpg”]
转化成imagedatas
比如
[{
presrc:“”,
src:null
}]
除了一开始的数量设置src为对应的图片地址,后面的都是设置null
然后在上拉触底事件触发的时候,再把后面的图片对象设置src=presrc!

然后就是高度的判断,有可能比如你配置每次加载3张图,如果这三张图的高度不够一屏,那体验上用户就能看到图片还在加载了!
所以代码上做了一个贪婪模式,就是图片load后,去计算本次加载的总高度,是否满足,不够的话再多懒加载一次!
看函数代码

 onImageLoad(e) {
      this.data.imageCount ++
      //又不用渲染UI 所以下面的代码没必要
      // this.setData({
      //   imageCount: this.data.imageCount
      // })

      if(e.detail){
        if(e.detail.height){
          //本张图片渲染的高度
          this.data.current_load_height+=e.detail.height;
        }
      }

      if(this.data.lazyload){
      //本次懒加载的图片已经加载完成了
      if(this.data.imageCount == this.data.loadcount){
        this.data.current_loaded_ok=true;
         this.triggerEvent('onImageLoad', this.data.imageCount);

         //未完待续 如果还可以继续加载,如果刚刚加载的总高度小于屏幕的总高度,则继续贪婪加载
         if(this.data.current_load_height<this.data.per_load_min_height){
           //本次渲染的高度太小了,看看是否可以继续渲染,再次渲染3张
           this.loadNext(this.data.per_load_count);
         }
      }
      }else{
        //非懒加载
        if(this.data.imageCount == this.data.imagedatas.length){
          this.triggerEvent('onImageLoad', this.data.imageCount);
        }
      }


      //如果渲染不够,还可以继续渲染
      // console.log(e);//可以通过e来计算本次加载是否足够,不够的话补足剩余的数量
    },
;