支持列表项内容高度不确定、简单易用的微信小程序长列表组件。
微信版本库 >= 1.9.3
在开始使用之前,你需要先阅读以下相关官方文档: 微信小程序自定义组件 的相关文档。
通过 npm
安装,需要依赖小程序基础库 2.2.1
以上版本,同时依赖开发者工具的 npm
构建,详见 npm 支持。
# Using npm
npm i wechat-long-list-chunk -S --production
# Using yarn
yarn add wechat-long-list-chunk --production
通过 GitHub 下载代码,然后将 miniprogram_dist
目录,拷贝到自己的项目中的组件目录,并重命名文件夹为组件名,例如wechat-long-list-chunk
。
git clone https://github.com/zhanghaoxu/wechat-long-list-chunk.git
cd wechat-long-list-chunk
一般业务场景下,列表数据都是有分页的,这种场景下,我们很容易构造二维数组,增量更新list
,这样可以有效提高setData
的性能。同时,这样可以减少chunk监听数量,提高效率。示例代码:
setData({
[`list[${this.data.list.length}]`] = nextPageList
})
- 通过npm方式安装(不要忘记在微信开发者工具进行构建)
"usingComponents": {
"wechat-long-list-chunk": "wechat-long-list-chunk"
}
- 通过直接复制模块到项目中的方式安装
"usingComponents": {
"wechat-long-list-chunk": "path/to/wechat-long-list-chunk"
}
<!--
@@param chunkId (type String)chunk唯一标识
@@param list (type Array) 实际业务列表数组
<card-list> 实际业务列表组件
-->
<wechat-long-list-chunk
wx:for="{{list}}"
wx:key="index"
chunkId="{{index}}">
<card-list list="{{item}}"></card-list>
</wechat-long-list-chunk>
虽然这个需求使用的不多,但支持同一页面多个长列表使用。
- (列表项高度不固定)长列表性能问题
长列表性能问题是前端业务领域经常遇到的问题。在web端和native端有成熟的“虚拟长列表”解决方案来解决长列表渲染的性能问题。
“虚拟长列表”是什么,如何实现,作者就不在这里赘述了,网上的教程一搜一大把;但其思想是真正能够解决实际问题的:通过动态改变可视区域上下部分区域的内容渲染,达到类似长列表浏览的体验,在列表不断变长的过程中,“虚拟长列表”相较于传统长列表具有明显的性能优势。
实际业务中的长列表可以分为两类:列表项目高度不固定、列表项目高度固定。
作者在参与的一些小程序项目中,遇到的很大一部分需求是列表项目不固定的,然鹅,微信社区所提供的一些解决方案如recycle-view并不能解决作者所遇到的问题。
实现列表项目高度不固定的虚拟长列表方案需要实现以下几个问题:
(1) 如何监听每一项的内容是否超高指定区域
与列表项目高度固定所不同,我们不能通过计算得到每一项所在的位置。因此,通过监听scroll事件是行不通的。
微信小程序从版本库1.9.3开始支持的InteractionObserver API可以解决我们的监听的问题。通过这个API,我们可以指定一个(可见区域上下的)固定监听区域,以此区域为参考点,监听每个item是否进入/离开此区域,以此控制item的渲染结果。
(2) 监听到item 进入/离开需要做哪些操作,以此达到类似“虚拟长列表”的效果?
首先,小程序是不能操作dom的,因此,不能通过动态修改padding/margin的方式来进行高度填充,作者想到的实现方案是将每一项item的高度进行记录,然后外层套一个空壳,当item离开监听区域时,卸载item的内容(释放相关内存),只保留一个空壳。
(3) 顺着上面的思路,如果每一项item都添加监听,成本是不是太高了?
是的。这里我们可以引入chunk(块)的概念,多个item形成一个chunk,对每个chunk进行监听,这样可以大幅减少监听成本。
(4) 分块如何去做?
一般的业务中,数据列表都是分页的,后一页的数据列表拼接到前面的数据,慢慢的,数据项变得越来越多。
我们知道小程序setData
在长列表中的一个优化手段是将一维数组转化为二维数组,这样可以对数据进行增量更新,大幅提高setData
的效率:
setData({
[`list[${this.data.list.length}]`] = nextPageList
})
而这里,也是我们进行chunk的地方,以上的以分页的数据进行chunk后,监听的单位变成chunk,而不再是item。
- 组件易用性问题
组件的易用性是很多开发者关心的问题。
我们想尽量以无侵入和低成本的方式引入解决方案,而对现有的业务影响没有影响。类似于高阶组件的思想,以外层组件进行能力扩展,通过插槽实现业务内容分发是一个通用的解决方式。
很可惜,小程序不支持类似于vue中的作用域插槽scopeSlot
,这意味着,我们无法将数据从外层组件传递数据到内层组件,数据的传递从能力扩展组件到实际业务组件断开了!这就导致无法对数据做一些额外的处理。(这里也希望微信官方加紧支持作用域插槽)
因此,我们不得不引入一种封装性不是特别好的方案:需要开发者自己书写循环语句:wx:for
。
用 微信web开发者工具 打开 tools/demo
目录(请注意,不是整个项目)。
有任何意见或建议都欢迎提 issue
MIT