新聞中心
recycle-view
小程序長列表組件

使用此組件需要依賴小程序基礎(chǔ)庫 2.2.2 版本,同時(shí)依賴開發(fā)者工具的 npm 構(gòu)建。具體詳情可查閱官方 npm 文檔。
背景
?目前小程序會(huì)有不少的應(yīng)用場景里會(huì)用到無限長列表的交互,當(dāng)一個(gè)頁面展示很多信息的時(shí)候,會(huì)造成小程序頁面的卡頓以及白屏。原因有如下幾點(diǎn):
- 列表數(shù)據(jù)很大,首次 setData 的時(shí)候耗時(shí)高
- 渲染出來的列表 DOM 結(jié)構(gòu)多,每次 setData 都需要?jiǎng)?chuàng)建新的虛擬樹、和舊樹 diff 操作耗時(shí)都比較高
- 渲染出來的列表 DOM 結(jié)構(gòu)多,占用的內(nèi)存高,造成頁面被系統(tǒng)回收的概率變大。
因此就有長列表組件來解決這些問題。
實(shí)現(xiàn)思路
?核心的思路是只渲染顯示在屏幕的數(shù)據(jù),基本實(shí)現(xiàn)就是監(jiān)聽 scroll 事件,并且重新計(jì)算需要渲染的數(shù)據(jù),不需要渲染的數(shù)據(jù)留一個(gè)空的 div 占位元素。
假設(shè)列表數(shù)據(jù)有100個(gè) item,知道了滾動(dòng)的位置,怎么知道哪些 item 必須顯示在頁面?因?yàn)?item 還沒渲染出來,不能通過 getComputedStyle 等 DOM 操作得到每個(gè) item 的位置,所以無法知道哪些 item 需要渲染。為了解決這個(gè)問題,需要每個(gè) item 固定寬高。item 的寬高的定義見下面的 API 的createRecycleContext()的參數(shù) itemSize 的介紹。
滾動(dòng)過程中,重新渲染數(shù)據(jù)的同時(shí),需要設(shè)置當(dāng)前數(shù)據(jù)的前后的 div 占位元素高度,同時(shí)是指在同一個(gè)渲染周期內(nèi)。頁面渲染是通過 setData 觸發(fā)的,列表數(shù)據(jù)和 div 占位高度在2個(gè)組件內(nèi)進(jìn)行 setData 的,為了把這2個(gè) setData 放在同一個(gè)渲染周期,用了一個(gè) hack 方法,所以定義 recycle-view 的 batch 屬性固定為 batch="{{batchSetRecycleData}}"。
在滾動(dòng)過程中,為了避免頻繁出現(xiàn)白屏,會(huì)多渲染當(dāng)前屏幕的前后2個(gè)屏幕的內(nèi)容。
包結(jié)構(gòu)
長列表組件由2個(gè)自定義組件 recycle-view、recycle-item 和一組 API 組成,對應(yīng)的代碼結(jié)構(gòu)如下
├── miniprogram-recycle-view/
└── recycle-view 組件
└── recycle-item 組件
└── index.js
包結(jié)構(gòu)詳細(xì)描述如下:
| 目錄/文件 | 描述 |
|---|---|
| recycle-view 組件 | 長列表組件 |
| recycle-item 組件 | 長列表每一項(xiàng) item 組件 |
| index.js | 提供操作長列表數(shù)據(jù)的API |
使用方法:
1.安裝組件
npm install --save miniprogram-recycle-view2.在頁面的 json 配置文件中添加 recycle-view 和 recycle-item 自定義組件的配置
{
"usingComponents": {
"recycle-view": "miniprogram-recycle-view/recycle-view",
"recycle-item": "miniprogram-recycle-view/recycle-item"
}
}3.WXML 文件中引用 recycle-view
長列表前面的內(nèi)容
{{item.idx+1}}. {{item.title}}
長列表后面的內(nèi)容
recycle-view 的屬性介紹如下:
| 字段名 | 類型 | 必填 | 描述 |
|---|---|---|---|
| id | String | 是 | id必須是頁面唯一的字符串 |
| batch | Boolean | 是 | 必須設(shè)置為{{batchSetRecycleData}}才能生效 |
| height | Number | 否 | 設(shè)置recycle-view的高度,默認(rèn)為頁面高度 |
| width | Number | 否 | 設(shè)置recycle-view的寬度,默認(rèn)是頁面的寬度 |
| enable-back-to-top | Boolean | 否 | 默認(rèn)為false,同scroll-view同名字段 |
| scroll-top | Number | 否 | 默認(rèn)為false,同scroll-view同名字段 |
| scroll-y | Number | 否 | 默認(rèn)為true,同scroll-view同名字段 |
| scroll-to-index | Number | 否 | 設(shè)置滾動(dòng)到長列表的項(xiàng) |
| placeholder-image | String | 否 | 默認(rèn)占位背景圖片,在渲染不及時(shí)的時(shí)候顯示,不建議使用大圖作為占位。建議傳入SVG的Base64格式,可使用工具將SVG代碼轉(zhuǎn)為Base64格式。支持SVG中設(shè)置rpx。 |
| scroll-with-animation | Boolean | 否 | 默認(rèn)為false,同scroll-view的同名字段 |
| lower-threshold | Number | 否 | 默認(rèn)為false,同scroll-view同名字段 |
| upper-threshold | Number | 否 | 默認(rèn)為false,同scroll-view同名字段 |
| bindscroll | 事件 | 否 | 同scroll-view同名字段 |
| bindscrolltolower | 事件 | 否 | 同scroll-view同名字段 |
| bindscrolltoupper | 事件 | 否 | 同scroll-view同名字段 |
recycle-view 包含3個(gè) slot,具體介紹如下:
| 名稱 | 描述 |
|---|---|
| before | 默認(rèn) slot 的前面的非回收區(qū)域 |
| 默認(rèn) slot | 長列表的列表展示區(qū)域,recycle-item 必須定義在默認(rèn) slot 中 |
| after | 默認(rèn) slot 的后面的非回收區(qū)域 |
長列表的內(nèi)容實(shí)際是在一個(gè) scroll-view 滾動(dòng)區(qū)域里面的,當(dāng)長列表里面的內(nèi)容,不止是單獨(dú)的一個(gè)列表的時(shí)候,例如我們頁面底部都會(huì)有一個(gè) copyright 的聲明,我們就可以把這部分的內(nèi)容放在 before 和 after 這2個(gè) slot 里面。
recycle-item 的介紹如下:
需要注意的是,recycle-item 中必須定義 wx:for 列表循環(huán),不應(yīng)該通過 setData 來設(shè)置 wx:for 綁定的變量,而是通過createRecycleContext方法創(chuàng)建RecycleContext對象來管理數(shù)據(jù),createRecycleContext在 index.js 文件里面定義。建議同時(shí)設(shè)置 wx:key,以提升列表的渲染性能。
4.頁面 JS 管理 recycle-view 的數(shù)據(jù)
const createRecycleContext = require('miniprogram-recycle-view')
Page({
onReady: function() {
var ctx = createRecycleContext({
id: 'recycleId',
dataKey: 'recycleList',
page: this,
itemSize: { // 這個(gè)參數(shù)也可以直接傳下面定義的this.itemSizeFunc函數(shù)
width: 162,
height: 182
}
})
ctx.append(newList)
// ctx.update(beginIndex, list)
// ctx.destroy()
},
itemSizeFunc: function (item, idx) {
return {
width: 162,
height: 182
}
}
})頁面必須通過 Component 構(gòu)造器定義,頁面引入了miniprogram-recycle-view包之后,會(huì)在 wx 對象下面新增接口createRecycleContext函數(shù)創(chuàng)建RecycleContext對象來管理 recycle-view 定義的的數(shù)據(jù),createRecycleContext接收類型為1個(gè) Object 的參數(shù),Object 參數(shù)的每一個(gè) key 的介紹如下:
| 參數(shù)名 | 類型 | 描述 |
|---|---|---|
| id | String | 對應(yīng) recycle-view 的 id 屬性的值 |
| dataKey | String | 對應(yīng) recycle-item 的 wx:for 屬性設(shè)置的綁定變量名 |
| page | Page/Component | recycle-view 所在的頁面或者組件的實(shí)例,頁面或者組件內(nèi)可以直接傳 this |
| itemSize | Object/Function | 此參數(shù)用來生成recycle-item的寬和高,前面提到過,要知道當(dāng)前需要渲染哪些item,必須知道item的寬高才能進(jìn)行計(jì)算 Object必須包含{width, height}兩個(gè)屬性,F(xiàn)unction的話接收item, index這2個(gè)參數(shù),返回一個(gè)包含{width, height}的Object itemSize如果是函數(shù),函數(shù)里面 this指向RecycleContext如果樣式使用了rpx,可以通過transformRpx來轉(zhuǎn)化為px。 為Object類型的時(shí)候,還有另外一種用法,詳細(xì)情況見下面的itemSize章節(jié)的介紹。 |
| useInPage | Boolean | 是否整個(gè)頁面只有recycle-view。Page的定義里面必須至少加空的onPageScroll函數(shù),主要是用在頁面級(jí)別的長列表,并且需要用到onPullDownRefresh的效果。切必須設(shè)置root參數(shù)為當(dāng)前頁面對象 |
| root | Page | 當(dāng)前頁面對象,可以通過getCurrentPages獲取, 當(dāng)useInPage為true必須提供 |
RecycleContext 對象提供的方法有:
| 方法 | 參數(shù) | 說明 |
|---|---|---|
| append | list, callback | 在當(dāng)前的長列表數(shù)據(jù)上追加list數(shù)據(jù),callback是渲染完成的回調(diào)函數(shù) |
| splice | begin, count, list, callback | 插入/刪除長列表數(shù)據(jù),參數(shù)同Array的splice函數(shù),callback是渲染完成的回調(diào)函數(shù) |
| update | begin, list, callback | 更新長列表的數(shù)據(jù),從索引參數(shù)begin開始,更新為參數(shù)list,參數(shù)callback同splice。 |
| destroy | 無 | 銷毀RecycleContext對象,在recycle-view銷毀的時(shí)候調(diào)用此方法 |
| forceUpdate | callback, reinitSlot | 重新渲染recycle-view。callback是渲染完成的回調(diào)函數(shù),當(dāng)before和after這2個(gè)slot的高度發(fā)生變化時(shí)候調(diào)用此函數(shù),reinitSlot設(shè)置為true。當(dāng)item的寬高發(fā)生變化的時(shí)候也需要調(diào)用此方法。 |
| getBoundingClientRect | index | 獲取某個(gè)數(shù)據(jù)項(xiàng)的在長列表中的位置,返回{left, top, width, height}的Object。 |
| getScrollTop | 無 | 獲取長列表的當(dāng)前的滾動(dòng)位置。 |
| transformRpx | rpx | 將rpx轉(zhuǎn)化為px,返回轉(zhuǎn)化后的px整數(shù)。itemSize返回的寬高單位是px,可以在這里調(diào)用此函數(shù)將rpx轉(zhuǎn)化為px,參數(shù)是Number,例如ctx.transformRpx(140),返回70。注意,transformRpx會(huì)進(jìn)行四舍五入,所以transformRpx(20) + transformRpx(90)不一定等于transformRpx(110) |
| getViewportItems | inViewportPx | 獲取在視窗內(nèi)的數(shù)據(jù)項(xiàng),用于判斷某個(gè)項(xiàng)是否出現(xiàn)在視窗內(nèi)。用于曝光數(shù)據(jù)上報(bào),菜品和類別的聯(lián)動(dòng)效果實(shí)現(xiàn)。參數(shù)inViewportPx表示距離屏幕多少像素為出現(xiàn)在屏幕內(nèi),可以為負(fù)值。 |
其中 itemSize 的使用
itemSize可以為包含{width, height}的Object,所有數(shù)據(jù)只有一種寬高信息。如果有多種,則可以提供一個(gè)函數(shù),長列表組件會(huì)調(diào)用這個(gè)函數(shù)生成每條數(shù)據(jù)的寬高信息,如下所示:
function(item, index) {
return {
width: 195,
height: item.azFirst ? 130 : 120
}
}提示:
- recycle-view設(shè)置batch屬性的值必須為{{batchSetRecycleData}}。
- recycle-item的寬高必須和itemSize設(shè)置的寬高一致,否則會(huì)出現(xiàn)跳動(dòng)的bug。
- recycle-view設(shè)置的高度必須和其style里面設(shè)置的樣式一致。
- createRecycleContext(options)的id參數(shù)必須和recycle-view的id屬性一致,dataKey參數(shù)必須和recycle-item的wx:for綁定的變量名一致。
- 不能在recycle-item里面使用wx:for的index變量作為索引值的,請使用{{item._index_}}替代。
- 不要通過setData設(shè)置recycle-item的wx:for的變量值,建議recycle-item設(shè)置wx:key屬性。
- 如果長列表里面包含圖片,必須保證圖片資源是有HTTP緩存的,否則在滾動(dòng)過程中會(huì)發(fā)起很多的圖片請求。
- 有些數(shù)據(jù)不一定會(huì)渲染出來,使用wx.createSelectorQuery的時(shí)候有可能會(huì)失效,可使用RecycleContext的getBoundingClientRect來替代。
- 當(dāng)使用了useInPage參數(shù)的時(shí)候,必須在Page里面定義onPageScroll事件。
- transformRpx會(huì)進(jìn)行四舍五入,所以transformRpx(20) + transformRpx(90)不一定等于transformRpx(110)
- 如果一個(gè)頁面有多個(gè)長列表,必須多設(shè)置batch-key屬性,每個(gè)的batch-key的值和batch屬性的變量必須不一致。例如
文章名稱:創(chuàng)新互聯(lián)小程序教程:微信小程序 擴(kuò)展組件·小程序長列表組件
路徑分享:http://m.fisionsoft.com.cn/article/dpcpjhi.html


咨詢
建站咨詢
