小程序分頁(yè)加載及瀑布流的實(shí)現(xiàn)

整體思路:在page/index.wxml頁(yè)面引入自定義好的瀑布流組件,通過page/index.js初始化一個(gè)Paging的實(shí)例對(duì)象,這個(gè)對(duì)象是主要是用于通過api獲取數(shù)據(jù)并記錄當(dāng)前請(qǐng)求狀態(tài)的。onload時(shí)預(yù)加載指定count數(shù)量的數(shù)據(jù),并將對(duì)象及對(duì)象返回的數(shù)據(jù)保存在data中,并通過瀑布流進(jìn)行渲染。當(dāng)觸發(fā)觸底事件時(shí),通過調(diào)用對(duì)象的getMoreData方法獲取下一批數(shù)據(jù)bin進(jìn)行渲染。

page/index.wxml:

<!--由于標(biāo)題頭圖基本不會(huì)改變,直接使用本地路徑獲取圖片-->
<view class="spu-bottom">
        <image src="../../img/xxx.png" class="spu-bottom-img"></image>
<!--根據(jù)lin-ui瀑布流組件要求,需通過generic:l-water-flow-item="xxx" 
      指定一個(gè)自定義組件,這個(gè)自定義組件即是要封裝展示的每一塊區(qū)域-->
<!--瀑布流組件內(nèi)置columns-gap,表示兩列數(shù)據(jù)之間的間隔。
        為了避免與我們自定義樣式類沖突,手動(dòng)設(shè)置為0-->
        <s-water-flow generic:l-water-flow-item="s-spu-preview" column-gap="0rpx"></s-water-flow>
 </view>

自定義組件s-spu-preview:

/*json部分主要是引入價(jià)格組件,方便wxml調(diào)用
{
  "component": true,
  "usingComponents": {
    "l-price": "../../miniprogram_npm/lin-ui/price/index"
  }
-------------------------------------------------------------
js部分主要是接受一個(gè)data數(shù)據(jù)。
Component({
  properties: {
      data:Object
  }....}
*/
<view class="container">
<!--頭圖-->
    <image src="{{data.img}}" mode="widthFix" class="image"></image>
<!--標(biāo)題-->
    <view class="title">{{data.title}}</view>
<!--價(jià)格-->
    <l-price color="#157658" value="{{data.price}}" l-class="price" size="32"></l-price>
<!--商品簡(jiǎn)介-->
    <view class="subtitle">{{data.subtitle}}</view>
</view>
}

page/index.js:

//主頁(yè)的js主要是用于數(shù)據(jù)的初始化、數(shù)據(jù)綁定、事件處理等。
page({
    data:{
        //用于渲染的數(shù)據(jù),返回的實(shí)際上是一個(gè)對(duì)象,
        //它具有一個(gè)items屬性(Array),我們渲染的既是這個(gè)列表。
        pagingData = null ,
        //這個(gè)paging是一個(gè)實(shí)例化對(duì)象,每次需要通過它來(lái)獲得新的數(shù)據(jù)
        paging = Object
    },
    onLoad:async function(){
        //Paging類主要進(jìn)行數(shù)據(jù)的請(qǐng)求發(fā)起處理。
        //其data屬性用于保存返回的結(jié)果,getMoreData()方法用于請(qǐng)求下一批數(shù)據(jù)。
        const paging = new Paging() 
        await paging.getMoreData()
        this.setData({
            pagingData:paging.data,
            paging:paging
        })
        //當(dāng)數(shù)據(jù)綁定完成后調(diào)用wx.lin.renderWaterFlow傳入數(shù)據(jù)進(jìn)行渲染
        wx.lin.renderWaterFlow(this.data.pagingData.items,false)
    },
    onReachBottom:function(){
        /*
        renderWaterflow渲染數(shù)據(jù)時(shí),refresh參數(shù)若為true,則會(huì)重新渲染一遍全部的數(shù)據(jù)。
        而設(shè)置為false時(shí)則會(huì)保留已渲染過的,將只渲染指定的數(shù)據(jù)。
        測(cè)試時(shí)設(shè)置true,重新渲染畫面會(huì)有閃爍的情況,體驗(yàn)較差。
        因此選擇了通過slice選擇選擇新增的數(shù)據(jù),并單獨(dú)渲染這部分?jǐn)?shù)據(jù)。
        */
        const total = this.data.pagingData.total //分頁(yè)加載api總體的數(shù)據(jù)量
        let start = this.data.paging.count //當(dāng)前已渲染過的數(shù)據(jù)量
         //每頁(yè)加載的數(shù)據(jù)量,在Paging類中定義,我們這里設(shè)置為3。         
        let end = start+3
        //每次新增加3個(gè)有可能會(huì)超出最大數(shù)據(jù)量范圍,通過三元表達(dá)式返回合適的結(jié)束值。        
        end = end>total?total:end
})
        await this.data.paging.getMoreData() //再獲取一批新的數(shù)據(jù)
        this.setData({pagingI:this.data.paging.data}) //同樣進(jìn)行數(shù)據(jù)綁定
        
        
        /*當(dāng)api擁有的數(shù)據(jù)全部渲染完以后,通過上面start和end邏輯
        可以看出來(lái)start和end是一定相等的。因此可以通過判斷這兩個(gè)值的關(guān)系決定是否完成了
        全部數(shù)據(jù)的渲染(不再繼續(xù)渲染新的數(shù)據(jù))*/
        //通過上面的的start和end,使用slice選擇新增加的那部分?jǐn)?shù)據(jù)并進(jìn)行渲染
        if(start!==end){
                wx.lin.renderWaterFlow(this.data.pagingI.items.slice(start,end),false)        
        }
}

Paging類:

import {Http} from "./Http"; 
//這個(gè)Http只是個(gè)封裝好api基地址、header認(rèn)證信息等信息的wx.request請(qǐng)求

class Paging {
    url;
    start;
    count;
    locker;
    data;
    lastcount;
   //構(gòu)造函數(shù)
   constructor(url,width = 3,start = 0){
      /*由于api參數(shù)分別需要提供請(qǐng)求的起始序號(hào)和終止序號(hào),
        而沒有分頁(yè)加載指定的每頁(yè)的數(shù)量,
        因此我們需要通過每頁(yè)加載數(shù)量來(lái)更新start和end。
      */
      this.url = url; 
      this.start = start;
      this.count = 0; //當(dāng)前總共請(qǐng)了多少條數(shù)據(jù)
      this.width = width; //每次請(qǐng)求幾條數(shù)據(jù)
      this.totalitems = 0; //是api中返回結(jié)果的total屬性的值,全部數(shù)量
   }
    async getMoreData() {
        if (this.count===this.totalitems && this.count!==0)
            //當(dāng)一次獲取記錄的條數(shù)count和api接口擁有的總體數(shù)量this.totalitems相同時(shí),結(jié)束請(qǐng)求。
            return ;
        //判斷當(dāng)前請(qǐng)求鎖的狀態(tài),如果this._getLocker()
        //返回true表示上一次請(qǐng)求已結(jié)束,可以繼續(xù)發(fā)起新的請(qǐng)求。
        if (this._getLocker()) {
            this.count = this.count+this.width; //更新count
            if(this.count>this.totalitems && this.totalitems!==0){
                //如過count已經(jīng)超過了數(shù)據(jù)的最大請(qǐng)求數(shù)量,則令count等于這個(gè)最大請(qǐng)求數(shù)量
                this.count=this.totalitems
            }
            const tmp_data = await Http.request({
                url: `${this.url}?start=${this.start}&count=${this.count}`
            });//發(fā)起新的請(qǐng)求
            this.start = this.count;//更新start
            if (~this.data) {
                //data是一個(gè)array,當(dāng)數(shù)組為空也就意味著這是第一次發(fā)起請(qǐng)求
                this.data = tmp_data;
                this.totalitems = tmp_data.total
            }
            else{
                //之后再次發(fā)起請(qǐng)求則將請(qǐng)求結(jié)果append到數(shù)組中即可
                this.data.append(tmp_data);
            }
            this._releaseLocker(); //請(qǐng)求完成,釋放鎖
            return
        }
        return false
    }
   _getLocker(){
       /*
        獲取鎖的狀態(tài)。若為鎖的狀態(tài)this.locker為false表示當(dāng)前沒有正在進(jìn)行中的請(qǐng)求,
        返回true表示允許發(fā)起新的請(qǐng)求,并將locker設(shè)置為true表示存在進(jìn)行中的請(qǐng)求。
        若鎖的狀態(tài)this.locker為true,則返回false表示已經(jīng)有處理中的請(qǐng)求了,
        不允許發(fā)出新的請(qǐng)求。
        */
       if (this.locker){
           return false
       }
       //鎖狀態(tài)為false,則另鎖狀態(tài)為true防止繼續(xù)點(diǎn)擊,并進(jìn)行request
       this.locker = true;
       return true
   }
   _releaseLocker(){
        //將鎖狀態(tài)置為false,代表上一次請(qǐng)求已經(jīng)完成,允許發(fā)出新的請(qǐng)求。
       this.locker = false
   }
}
export {Paging}

只是做了個(gè)大致的效果,其他的觸底狀態(tài)顯示、觸發(fā)距離等未做優(yōu)化,大致效果如下:


Jietu20191208-171535.gif
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容