小編給大家分享一下小程序中如何編寫可復用分頁組件,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
項目中遇到 tab切換列表,每個tab都需要分頁的需求,分頁流程具有相似性,于是想將分頁封裝為組件,方便應用。
組件的應用已寫成一個小demo,效果如下圖所示(數據用mock模擬):

源碼可以查看:wxapp-pagination
項目需求
具體項目需求:
查看自己相關的會議(頁面命名為 meetings)
tab切換,分為:
“我的會議”(我參加的會議,后面會以 "join" 為 key區分)
“我的預約”(我預約的會議,后面會以 "book" 為 key區分)
一次加載10條(size=10),拉到底部后,加載下一頁(page = page +1)
當然,作為前端,要考慮性能方面的需求:
首次只加載默認tab頁的首頁,其他tab等到點擊到對應tab才開始加載。
回到已加載過的tab頁,保留原數據不重新加載。
所以原型圖大概就長這樣:

邏輯實現
與分頁邏輯相關的項目結構如下:
├── components │ ├── meeting-item # 列表item │ └── pagination # 分頁組件 ├── model │ └── user.js # 我的相關 model └── pages │ └── user # 我的相關頁面 │ ├── meetings # 我的會議(就是tab要分頁的頁面啦) │ └── ... │ └── vant-weapp
還是用圖理一下他們之間的關系吧:

在組件內監聽觸發分頁事件
觸發分頁的事件是滾動到頁面的底部,小程序中,觸發該事件是Page頁面的onReachBottom事件,但是這個事件只能在Page中觸發,所以要將這個觸發時機傳遞給pagination組件。
解決思路是:組件 pagination 內,設置key屬性,每當onReachBottom事件觸發之后,設置組件屬性 key 為一個隨機字符串,當組件 pagination 監聽到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="我的預約">
<view class="meeting-list">
<pagination
name="BOOK"
key="{{bookKey}}"
>
</pagination>
</view>
</tab>
</tabs>Page({
onReachBottom(){
const key = scene[+this.data.currentTab].key // 對應tab對應key
this.setData({
[key]: random(16)
})
}
})分頁組件的實現邏輯
觸發到達底部之后,需要加載數據。但再加載之前,先滿足加載的條件:
上一頁還未加載完成(loading = true),不重復加載
當前頁面全部加載完(ended = true),不繼續加載
具體加載流程為:
page:觸發 onReachBottom 事件,修改 pagination組件 key 值
component: key值監聽到變化,觸發加載事件 _loadMoreData
component: _loadMoreData 中判斷滿足條件后,觸發加載列表函數 this.triggerEvent('getList'),并傳入頁面參數page 和 size。
page:向model層獲取數據。
page:獲取數據后,傳遞給 pagination組件list和total 值。
component:list 監聽到變化,判斷是否加載完成。
component
// components/pagination/index.js
Component({
properties: {
name: String,
key: {
type: String,
observer: '_loadMoreData' // _loadMoreData 為分頁操作
},
size: { // 每次加載條目數
type: Number,
value: 10
},
total: Number, // 頁面總數
list: { // 已加載條目
type: Array,
observer: '_endState' // 每次加載完新數據,判斷數據是否全部加載完成
}
},
data: {
page: 0, // 當前第幾頁
loading: false, // 是否正在加載
ended: false // 數據是否已全部加載完成
},
methods: {
_loadMoreData(){
const { loading, ended, size } = this.data
if (loading) return // 上一頁還未加載完成,不加載
if (ended) return // 當前頁面全部加載完,不加載
const page = this.data.page + 1
this.setData({
loading: true, // 開始加載新頁面loading設置為true
page
})
// 觸發加載下一頁,并傳入參數
this.triggerEvent('getList', {
page,
size
})
},
_endState(val, oldVal) {
const { total, list } = this.properties
let ended = false
// 判斷數據是否全部加載完成
if (list.length >= total) {
ended = true
}
this.setData({
loading: false, // 當前頁面加載完成,loading設置為false
ended
})
}
}
})page
<!-- pages/user/meetings/index.wxml -->
<pagination
name="BOOK"
key="{{bookKey}}"
bind:getList="getBookMeetings"
list="{{bookMeetings}}"
total="{{bookTotal}}"
>
</pagination>循環列表item
pagination組件獲取了可循環的列表,初始想法是循環slot,但是在slot中卻獲取不到 item 對象:
<view wx:for="{{list}}" wx:for-item="item" wx:key="index">
<slot></slot>
</view>解決的辦法是將每個列表項封裝為組件,循環抽象節點,這樣對其他頁面的分頁具有可拓展性。
componentGenerics 字段中聲明:
// components/pagination/index.json
{
"componentGenerics": {
"selectable": true
},
// ...
}使用抽象節點:
<!-- 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>
對應 json 文件定義對應 usingComponents :
// pages/user/meetings/index.json
{
"usingComponents": {
"pagination":"/components/pagination/index",
"meeting-item":"/components/meeting-item/index"
}
}meeting-item 組件接收一個屬性 item,這樣在 meeting-item 組件中,就可以獲取到循環列表的item值,并正常繪制頁面。
實現切換懶加載
給pagination添加initImmediately屬性,當initImmediately為true時,首次加載頁面,并用變量 initState標記是否已經初始化頁面過。
// components/pagination/index.js
Component({
properties: {
initImmediately: {
type: Boolean,
value: true,
observer: function(val){
if (val && !this.data.initState) {
this.initData()
}
}
},
// ...
},
data: {
initState: false, // 是否已經加載過
// ...
},
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
// ...
},
}
})當currentTab為當前類型的時候,initImmediately 設置為 true。
<!-- pages/user/meetings/index.wxml -->
<pagination
name="JOIN"
init-immediately="{{currentTab==type['JOIN']}}"
// ...
>
</pagination>
<pagination
name="BOOK"
init-immediately="{{currentTab==type['BOOK']}}"
// ...
>
</pagination>組件的復用
完成了以上組件,在對其他分頁的頁面,可以直接復用。比如,實現一個獲取全部用戶列表的分頁,只需要新增一個user-item的組件,像這樣調用:
<pagination
name="USER"
key="{{key}}"
bind:getList="getUserList"
list="{{userList}}"
total="{{userTotal}}"
generic:selectable="user-item"
>
</pagination>具體應用可以查看我寫的小demo:wxapp-pagination。
以上是“小程序中如何編寫可復用分頁組件”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。