小程序分页加载及瀑布流的实现

整体思路:在page/index.wxml页面引入自定义好的瀑布流组件,通过page/index.js初始化一个Paging的实例对象,这个对象是主要是用于通过api获取数据并记录当前请求状态的。onload时预加载指定count数量的数据,并将对象及对象返回的数据保存在data中,并通过瀑布流进行渲染。当触发触底事件时,通过调用对象的getMoreData方法获取下一批数据bin进行渲染。

page/index.wxml:



        


        
 

自定义组件s-spu-preview:

/*json部分主要是引入价格组件,方便wxml调用
{
  "component": true,
  "usingComponents": {
    "l-price": "../../miniprogram_npm/lin-ui/price/index"
  }
-------------------------------------------------------------
js部分主要是接受一个data数据。
Component({
  properties: {
      data:Object
  }....}
*/


    

    {{data.title}}

    

    {{data.subtitle}}

}

page/index.js:

//主页的js主要是用于数据的初始化、数据绑定、事件处理等。
page({
    data:{
        //用于渲染的数据,返回的实际上是一个对象,
        //它具有一个items属性(Array),我们渲染的既是这个列表。
        pagingData = null ,
        //这个paging是一个实例化对象,每次需要通过它来获得新的数据
        paging = Object
    },
    onLoad:async function(){
        //Paging类主要进行数据的请求发起处理。
        //其data属性用于保存返回的结果,getMoreData()方法用于请求下一批数据。
        const paging = new Paging() 
        await paging.getMoreData()
        this.setData({
            pagingData:paging.data,
            paging:paging
        })
        //当数据绑定完成后调用wx.lin.renderWaterFlow传入数据进行渲染
        wx.lin.renderWaterFlow(this.data.pagingData.items,false)
    },
    onReachBottom:function(){
        /*
        renderWaterflow渲染数据时,refresh参数若为true,则会重新渲染一遍全部的数据。
        而设置为false时则会保留已渲染过的,将只渲染指定的数据。
        测试时设置true,重新渲染画面会有闪烁的情况,体验较差。
        因此选择了通过slice选择选择新增的数据,并单独渲染这部分数据。
        */
        const total = this.data.pagingData.total //分页加载api总体的数据量
        let start = this.data.paging.count //当前已渲染过的数据量
         //每页加载的数据量,在Paging类中定义,我们这里设置为3。         
        let end = start+3
        //每次新增加3个有可能会超出最大数据量范围,通过三元表达式返回合适的结束值。        
        end = end>total?total:end
})
        await this.data.paging.getMoreData() //再获取一批新的数据
        this.setData({pagingI:this.data.paging.data}) //同样进行数据绑定
        
        
        /*当api拥有的数据全部渲染完以后,通过上面start和end逻辑
        可以看出来start和end是一定相等的。因此可以通过判断这两个值的关系决定是否完成了
        全部数据的渲染(不再继续渲染新的数据)*/
        //通过上面的的start和end,使用slice选择新增加的那部分数据并进行渲染
        if(start!==end){
                wx.lin.renderWaterFlow(this.data.pagingI.items.slice(start,end),false)        
        }
}

Paging类:

import {Http} from "./Http"; 
//这个Http只是个封装好api基地址、header认证信息等信息的wx.request请求

class Paging {
    url;
    start;
    count;
    locker;
    data;
    lastcount;
   //构造函数
   constructor(url,width = 3,start = 0){
      /*由于api参数分别需要提供请求的起始序号和终止序号,
        而没有分页加载指定的每页的数量,
        因此我们需要通过每页加载数量来更新start和end。
      */
      this.url = url; 
      this.start = start;
      this.count = 0; //当前总共请了多少条数据
      this.width = width; //每次请求几条数据
      this.totalitems = 0; //是api中返回结果的total属性的值,全部数量
   }
    async getMoreData() {
        if (this.count===this.totalitems && this.count!==0)
            //当一次获取记录的条数count和api接口拥有的总体数量this.totalitems相同时,结束请求。
            return ;
        //判断当前请求锁的状态,如果this._getLocker()
        //返回true表示上一次请求已结束,可以继续发起新的请求。
        if (this._getLocker()) {
            this.count = this.count+this.width; //更新count
            if(this.count>this.totalitems && this.totalitems!==0){
                //如过count已经超过了数据的最大请求数量,则令count等于这个最大请求数量
                this.count=this.totalitems
            }
            const tmp_data = await Http.request({
                url: `${this.url}?start=${this.start}&count=${this.count}`
            });//发起新的请求
            this.start = this.count;//更新start
            if (~this.data) {
                //data是一个array,当数组为空也就意味着这是第一次发起请求
                this.data = tmp_data;
                this.totalitems = tmp_data.total
            }
            else{
                //之后再次发起请求则将请求结果append到数组中即可
                this.data.append(tmp_data);
            }
            this._releaseLocker(); //请求完成,释放锁
            return
        }
        return false
    }
   _getLocker(){
       /*
        获取锁的状态。若为锁的状态this.locker为false表示当前没有正在进行中的请求,
        返回true表示允许发起新的请求,并将locker设置为true表示存在进行中的请求。
        若锁的状态this.locker为true,则返回false表示已经有处理中的请求了,
        不允许发出新的请求。
        */
       if (this.locker){
           return false
       }
       //锁状态为false,则另锁状态为true防止继续点击,并进行request
       this.locker = true;
       return true
   }
   _releaseLocker(){
        //将锁状态置为false,代表上一次请求已经完成,允许发出新的请求。
       this.locker = false
   }
}
export {Paging}

只是做了个大致的效果,其他的触底状态显示、触发距离等未做优化,大致效果如下:


Jietu20191208-171535.gif

你可能感兴趣的:(小程序分页加载及瀑布流的实现)