溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

小程序中如何編寫可復(fù)用分頁組件

發(fā)布時間:2021-07-05 11:40:58 來源:億速云 閱讀:441 作者:小新 欄目:web開發(fā)

小編給大家分享一下小程序中如何編寫可復(fù)用分頁組件,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

項目中遇到 tab切換列表,每個tab都需要分頁的需求,分頁流程具有相似性,于是想將分頁封裝為組件,方便應(yīng)用。

組件的應(yīng)用已寫成一個小demo,效果如下圖所示(數(shù)據(jù)用mock模擬):

小程序中如何編寫可復(fù)用分頁組件

源碼可以查看:wxapp-pagination

項目需求

具體項目需求:

  • 查看自己相關(guān)的會議(頁面命名為 meetings)

  • tab切換,分為:

    • “我的會議”(我參加的會議,后面會以 "join" 為 key區(qū)分)

    • “我的預(yù)約”(我預(yù)約的會議,后面會以 "book" 為 key區(qū)分)

  • 一次加載10條(size=10),拉到底部后,加載下一頁(page = page +1)

當(dāng)然,作為前端,要考慮性能方面的需求:

  • 首次只加載默認(rèn)tab頁的首頁,其他tab等到點擊到對應(yīng)tab才開始加載。

  • 回到已加載過的tab頁,保留原數(shù)據(jù)不重新加載。

所以原型圖大概就長這樣:

小程序中如何編寫可復(fù)用分頁組件

邏輯實現(xiàn)

與分頁邏輯相關(guān)的項目結(jié)構(gòu)如下:

├── components
│    ├── meeting-item   # 列表item
│    └── pagination      # 分頁組件
├── model
│  └── user.js          # 我的相關(guān) model
└── pages
│    └── user            # 我的相關(guān)頁面
│    ├── meetings    # 我的會議(就是tab要分頁的頁面啦)
│    └── ...
│
└── vant-weapp

還是用圖理一下他們之間的關(guān)系吧:

小程序中如何編寫可復(fù)用分頁組件

在組件內(nèi)監(jiān)聽觸發(fā)分頁事件

觸發(fā)分頁的事件是滾動到頁面的底部,小程序中,觸發(fā)該事件是Page頁面的onReachBottom事件,但是這個事件只能在Page中觸發(fā),所以要將這個觸發(fā)時機傳遞給pagination組件。

解決思路是:組件 pagination 內(nèi),設(shè)置key屬性,每當(dāng)onReachBottom事件觸發(fā)之后,設(shè)置組件屬性 key  為一個隨機字符串,當(dāng)組件 pagination 監(jiān)聽到key的變化的時候,做出分頁操作。

// components/pagination/index.js
Component({
 properties: {
  key: {
   type: String,
   observer: '_loadMoreData' // _loadMoreData 為分頁操作
  }
 }
})
<!-- pages/user/meetings/index.wxml -->
<tabs active="{{currentTab}}" bind:change="onChange">
  <tab title="我的會議" data-key="{{type['JOIN']}}">
   <view class="meeting-list">
     <pagination 
      name="JOIN"
      key="{{joinKey}}" 
     >
     </pagination>
   </view>
  </tab>

  <tab title="我的預(yù)約">
   <view class="meeting-list">
    <pagination 
     name="BOOK"
     key="{{bookKey}}"
    >
    </pagination>
   </view>
  </tab>
</tabs>
Page({
 onReachBottom(){
  const key = scene[+this.data.currentTab].key // 對應(yīng)tab對應(yīng)key
  this.setData({
   [key]: random(16)
  })
 }
})

分頁組件的實現(xiàn)邏輯

觸發(fā)到達底部之后,需要加載數(shù)據(jù)。但再加載之前,先滿足加載的條件:

  • 上一頁還未加載完成(loading = true),不重復(fù)加載

  • 當(dāng)前頁面全部加載完(ended = true),不繼續(xù)加載

具體加載流程為:

  1. page:觸發(fā) onReachBottom 事件,修改 pagination組件 key 值

  2. component: key值監(jiān)聽到變化,觸發(fā)加載事件 _loadMoreData

  3. component: _loadMoreData 中判斷滿足條件后,觸發(fā)加載列表函數(shù) this.triggerEvent('getList'),并傳入頁面參數(shù)page 和 size。

  4. page:向model層獲取數(shù)據(jù)。

  5. page:獲取數(shù)據(jù)后,傳遞給 pagination組件list和total 值。

  6. component:list 監(jiān)聽到變化,判斷是否加載完成。

component

// components/pagination/index.js
Component({
 properties: {
  name: String,
  key: {
   type: String,
   observer: '_loadMoreData' // _loadMoreData 為分頁操作
  },
  size: { // 每次加載條目數(shù)
   type: Number,
   value: 10
  },
  total: Number, // 頁面總數(shù)
  list: {         // 已加載條目
   type: Array,
   observer: '_endState'   // 每次加載完新數(shù)據(jù),判斷數(shù)據(jù)是否全部加載完成
  }
 },

 data: {
  page: 0,        // 當(dāng)前第幾頁
  loading: false, // 是否正在加載
  ended: false  // 數(shù)據(jù)是否已全部加載完成
 },
 
 methods: {
  _loadMoreData(){
   const { loading, ended, size } = this.data
   if (loading) return // 上一頁還未加載完成,不加載
   if (ended) return  // 當(dāng)前頁面全部加載完,不加載
   const page = this.data.page + 1

   this.setData({
    loading: true, // 開始加載新頁面loading設(shè)置為true
    page
   })
   // 觸發(fā)加載下一頁,并傳入?yún)?shù)
   this.triggerEvent('getList', {
    page,
    size
   })
  },
  _endState(val, oldVal) {
   const { total, list } = this.properties
   let ended = false
   // 判斷數(shù)據(jù)是否全部加載完成
   if (list.length >= total) {
    ended = true
   }
   this.setData({
    loading: false, // 當(dāng)前頁面加載完成,loading設(shè)置為false
    ended
   })
  }
 }
})

page

<!-- pages/user/meetings/index.wxml -->
<pagination 
 name="BOOK"
 key="{{bookKey}}"
 bind:getList="getBookMeetings"
 list="{{bookMeetings}}"
 total="{{bookTotal}}"
>
</pagination>

循環(huán)列表item

pagination組件獲取了可循環(huán)的列表,初始想法是循環(huán)slot,但是在slot中卻獲取不到 item 對象:

<view wx:for="{{list}}" wx:for-item="item" wx:key="index">
 <slot></slot>
</view>

解決的辦法是將每個列表項封裝為組件,循環(huán)抽象節(jié)點,這樣對其他頁面的分頁具有可拓展性。

componentGenerics 字段中聲明:

// components/pagination/index.json
{
 "componentGenerics": {
  "selectable": true
 },
 // ...
}

使用抽象節(jié)點:

<!-- components/pagination/index.wxml -->
<view wx:for="{{list}}" wx:for-item="item" wx:key="index">
  <selectable item="{{item}}"></selectable>
</view>

指定“selectable”具體是哪個組件:

<!-- pages/user/meetings/index.wxml -->
<pagination 
 generic:selectable="meeting-item"
  // ... 其他屬性
>
</pagination>

對應(yīng) json 文件定義對應(yīng) usingComponents :

// pages/user/meetings/index.json
{
 "usingComponents": {
  "pagination":"/components/pagination/index",
  "meeting-item":"/components/meeting-item/index"
 }
}

meeting-item 組件接收一個屬性 item,這樣在 meeting-item 組件中,就可以獲取到循環(huán)列表的item值,并正常繪制頁面。

實現(xiàn)切換懶加載

給pagination添加initImmediately屬性,當(dāng)initImmediately為true時,首次加載頁面,并用變量 initState標(biāo)記是否已經(jīng)初始化頁面過。

// components/pagination/index.js
Component({
 properties: {
  initImmediately: {
   type: Boolean,
   value: true,
   observer: function(val){
    if (val && !this.data.initState) {
     this.initData()
    }
   }
  },
  // ...
 },
 data: {
   initState: false, // 是否已經(jīng)加載過
   // ...
 },
 lifetimes: {
  attached: function () {
   if (this.data.initImmediately){
    this.initData()
   }
  },
 },
 methods: {
  initData(){
   console.info(`${this.data.name}:start init data`)
   this._loadMoreData()
   this.setData({
    initState: true
   })  
   },
  // ... 
   _endState(val, oldVal) {
   if (!this.data.initState) return 
   // ...
   },
 }
})

當(dāng)currentTab為當(dāng)前類型的時候,initImmediately 設(shè)置為 true。

<!-- pages/user/meetings/index.wxml -->
<pagination 
  name="JOIN"
  init-immediately="{{currentTab==type['JOIN']}}"
  // ...
>
</pagination>

<pagination 
  name="BOOK"
  init-immediately="{{currentTab==type['BOOK']}}"
  // ...
>
</pagination>

組件的復(fù)用

完成了以上組件,在對其他分頁的頁面,可以直接復(fù)用。比如,實現(xiàn)一個獲取全部用戶列表的分頁,只需要新增一個user-item的組件,像這樣調(diào)用:

<pagination 
 name="USER"
 key="{{key}}" 
 bind:getList="getUserList" 
 list="{{userList}}" 
 total="{{userTotal}}"
 generic:selectable="user-item"
>
</pagination>

具體應(yīng)用可以查看我寫的小demo:wxapp-pagination。

以上是“小程序中如何編寫可復(fù)用分頁組件”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI