• Stars
    star
    620
  • Rank 72,387 (Top 2 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created over 6 years ago
  • Updated about 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

recycle-view: a wechat miniprogram custom component

recycle-view

小程序自定义组件

使用此组件需要依赖小程序基础库 2.2.2 版本,同时依赖开发者工具的 npm 构建。具体详情可查阅官方 npm 文档

背景

​ 电商小程序往往需要展示很多商品,当一个页面展示很多的商品信息的时候,会造成小程序页面的卡顿以及白屏。原因有如下几点:

  1. 商品列表数据很大,首次 setData 的时候耗时高
  2. 渲染出来的商品列表 DOM 结构多,每次 setData 都需要创建新的虚拟树、和旧树 diff 操作耗时都比较高
  3. 渲染出来的商品列表 DOM 结构多,占用的内存高,造成页面被系统回收的概率变大。

因此实现长列表组件来解决这些问题。

实现思路

​ 核心的思路就是只渲染显示在屏幕的数据,基本实现就是监听 scroll 事件,并且重新计算需要渲染的数据,不需要渲染的数据留一个空的 div 占位元素。

​ 假设列表数据有100个 item,知道了滚动的位置,怎么知道哪些 item 必须显示在页面?因为 item 还没渲染出来,不能通过 getComputedStyle 等 DOM 操作得到每个 item 的位置,所以无法知道哪些 item 需要渲染。为了解决这个问题,需要每个 item 固定宽高。item 的宽高的定义见下面的 API 的createRecycleContext()的参数 itemSize 的介绍。

​ 滚动过程中,重新渲染数据的同时,需要设置当前数据的前后的 div 占位元素高度,同时是指在同一个渲染周期内。页面渲染是通过 setData 触发的,列表数据和 div 占位高度在2个组件内进行 setData 的,为了把这2个 setData 放在同一个渲染周期,用了一个 hack 方法,所以定义 recycle-view 的 batch 属性固定为batch="{{batchSetRecycleData}}"

​ 在滚动过程中,为了避免频繁出现白屏,会多渲染当前屏幕的前后2个屏幕的内容。

包结构

长列表组件由2个自定义组件 recycle-view、recycle-item 和一组 API 组成,对应的代码结构如下

├── miniprogram-recycle-view/
    └── recycle-view 组件
    └── recycle-item 组件
    └── index.js

包结构详细描述如下:

目录/文件 描述
recycle-view 组件 长列表组件
recycle-item 组件 长列表每一项 item 组件
index.js 提供操作长列表数据的API

使用方法

  1. 安装组件
npm install --save miniprogram-recycle-view
  1. 在页面的 json 配置文件中添加 recycle-view 和 recycle-item 自定义组件的配置

    {
      "usingComponents": {
        "recycle-view": "miniprogram-recycle-view/recycle-view",
        "recycle-item": "miniprogram-recycle-view/recycle-item"
      }
    }
  2. WXML 文件中引用 recycle-view

    <recycle-view batch="{{batchSetRecycleData}}" id="recycleId">
      <view slot="before">长列表前面的内容</view>
      <recycle-item wx:for="{{recycleList}}" wx:key="id">
        <view>
            <image style='width:80px;height:80px;float:left;' src="{{item.image_url}}"></image>
          {{item.idx+1}}. {{item.title}}
        </view>
      </recycle-item>
      <view slot="after">长列表后面的内容</view>
    </recycle-view>

    recycle-view 的属性介绍如下:

    字段名 类型 必填 描述
    id String id必须是页面唯一的字符串
    batch Boolean 必须设置为{{batchSetRecycleData}}才能生效
    height Number 设置recycle-view的高度,默认为页面高度
    width Number 设置recycle-view的宽度,默认是页面的宽度
    enable-back-to-top Boolean 默认为false,同scroll-view同名字段
    scroll-top Number 默认为false,同scroll-view同名字段
    scroll-y Number 默认为true,同scroll-view同名字段
    scroll-to-index Number 设置滚动到长列表的项
    placeholder-image String 默认占位背景图片,在渲染不及时的时候显示,不建议使用大图作为占位。建议传入SVG的Base64格式,可使用工具将SVG代码转为Base64格式。支持SVG中设置rpx。
    scroll-with-animation Boolean 默认为false,同scroll-view的同名字段
    lower-threshold Number 默认为false,同scroll-view同名字段
    upper-threshold Number 默认为false,同scroll-view同名字段
    bindscroll 事件 同scroll-view同名字段
    bindscrolltolower 事件 同scroll-view同名字段
    bindscrolltoupper 事件 同scroll-view同名字段

    recycle-view 包含3个 slot,具体介绍如下:

    名称 描述
    before 默认 slot 的前面的非回收区域
    默认 slot 长列表的列表展示区域,recycle-item 必须定义在默认 slot 中
    after 默认 slot 的后面的非回收区域

    ​ 长列表的内容实际是在一个 scroll-view 滚动区域里面的,当长列表里面的内容,不止是单独的一个列表的时候,例如我们页面底部都会有一个 copyright 的声明,我们就可以把这部分的内容放在 before 和 after 这2个 slot 里面。

    recycle-item 的介绍如下:

    ​ 需要注意的是,recycle-item 中必须定义 wx:for 列表循环,不应该通过 setData 来设置 wx:for 绑定的变量,而是通过createRecycleContext方法创建RecycleContext对象来管理数据,createRecycleContext在 index.js 文件里面定义。建议同时设置 wx:key,以提升列表的渲染性能。

  3. 页面 JS 管理 recycle-view 的数据

    const createRecycleContext = require('miniprogram-recycle-view')
    Page({
        onReady: function() {
            var ctx = createRecycleContext({
              id: 'recycleId',
              dataKey: 'recycleList',
              page: this,
              itemSize: { // 这个参数也可以直接传下面定义的this.itemSizeFunc函数
                width: 162,
                height: 182
              }
            })
            ctx.append(newList)
            // ctx.update(beginIndex, list)
            // ctx.destroy()
        },
        itemSizeFunc: function (item, idx) {
            return {
                width: 162,
                height: 182
            }
        }
    })

    typescript支持,使用如下方式引入

    import * as createRecycleContext from 'miniprogram-recycle-view';

    ​ 页面必须通过 Component 构造器定义,页面引入了miniprogram-recycle-view包之后,会在 wx 对象下面新增接口createRecycleContext函数创建RecycleContext对象来管理 recycle-view 定义的的数据,createRecycleContext接收类型为1个 Object 的参数,Object 参数的每一个 key 的介绍如下:

    参数名 类型 描述
    id String 对应 recycle-view 的 id 属性的值
    dataKey String 对应 recycle-item 的 wx:for 属性设置的绑定变量名
    page Page/Component recycle-view 所在的页面或者组件的实例,页面或者组件内可以直接传 this
    itemSize Object/Function 此参数用来生成recycle-item的宽和高,前面提到过,要知道当前需要渲染哪些item,必须知道item的宽高才能进行计算
    Object必须包含{width, height}两个属性,Function的话接收item, index这2个参数,返回一个包含{width, height}的Object
    itemSize如果是函数,函数里面this指向RecycleContext
    如果样式使用了rpx,可以通过transformRpx来转化为px。
    为Object类型的时候,还有另外一种用法,详细情况见下面的itemSize章节的介绍。
    useInPage Boolean 是否整个页面只有recycle-view。Page的定义里面必须至少加空的onPageScroll函数,主要是用在页面级别的长列表,并且需要用到onPullDownRefresh的效果。切必须设置root参数为当前页面对象
    root Page 当前页面对象,可以通过getCurrentPages获取, 当useInPage为true必须提供

    RecycleContext 对象提供的方法有:

    方法 参数 说明
    append list, callback 在当前的长列表数据上追加list数据,callback是渲染完成的回调函数
    splice begin, count, list, callback 插入/删除长列表数据,参数同Array的splice函数,callback是渲染完成的回调函数
    update begin, list, callback 更新长列表的数据,从索引参数begin开始,更新为参数list,参数callback同splice。
    destroy 销毁RecycleContext对象,在recycle-view销毁的时候调用此方法
    forceUpdate callback, reinitSlot 重新渲染recycle-view。callback是渲染完成的回调函数,当before和after这2个slot的高度发生变化时候调用此函数,reinitSlot设置为true。当item的宽高发生变化的时候也需要调用此方法。
    getBoundingClientRect index 获取某个数据项的在长列表中的位置,返回{left, top, width, height}的Object。
    getScrollTop 获取长列表的当前的滚动位置。
    transformRpx rpx 将rpx转化为px,返回转化后的px整数。itemSize返回的宽高单位是px,可以在这里调用此函数将rpx转化为px,参数是Number,例如ctx.transformRpx(140),返回70。注意,transformRpx会进行四舍五入,所以transformRpx(20) + transformRpx(90)不一定等于transformRpx(110)
    getViewportItems inViewportPx 获取在视窗内的数据项,用于判断某个项是否出现在视窗内。用于曝光数据上报,菜品和类别的联动效果实现。参数inViewportPx表示距离屏幕多少像素为出现在屏幕内,可以为负值。
    getList 获取到完整的数据列表

    itemSize使用

    itemSize可以为包含{width, height}的Object,所有数据只有一种宽高信息。如果有多种,则可以提供一个函数,长列表组件会调用这个函数生成每条数据的宽高信息,如下所示:

    function(item, index) {
        return {
            width: 195,
            height: item.azFirst ? 130 : 120
        }
    }

    Tips

    1. recycle-view设置batch属性的值必须为{{batchSetRecycleData}}。
    2. recycle-item的宽高必须和itemSize设置的宽高一致,否则会出现跳动的bug。
    3. recycle-view设置的高度必须和其style里面设置的样式一致。
    4. createRecycleContext(options)的id参数必须和recycle-view的id属性一致,dataKey参数必须和recycle-item的wx:for绑定的变量名一致。
    5. 不能在recycle-item里面使用wx:for的index变量作为索引值的,请使用{{item.__index__}}替代。
    6. 不要通过setData设置recycle-item的wx:for的变量值,建议recycle-item设置wx:key属性。
    7. 如果长列表里面包含图片,必须保证图片资源是有HTTP缓存的,否则在滚动过程中会发起很多的图片请求。
    8. 有些数据不一定会渲染出来,使用wx.createSelectorQuery的时候有可能会失效,可使用RecycleContext的getBoundingClientRect来替代。
    9. 当使用了useInPage参数的时候,必须在Page里面定义onPageScroll事件。
  4. transformRpx会进行四舍五入,所以transformRpx(20) + transformRpx(90)不一定等于transformRpx(110)

  5. 如果一个页面有多个长列表,必须多设置batch-key属性,每个的batch-key的值和batch属性的变量必须不一致。例如

<recycle-view batch="{{batchSetRecycleData}}" batch-key="batchSetRecycleData"></recycle-view>
<recycle-view batch="{{batchSetRecycleData1}}" batch-key="batchSetRecycleData1"></recycle-view>

More Repositories

1

miniprogram-demo

微信小程序组件 / API / 云开发示例
JavaScript
6,576
star
2

minigame-unity-webgl-transform

Wechat Mini Game Unity engine adapter documents.
C
2,856
star
3

weui-miniprogram

小程序WeUI组件库
TypeScript
2,070
star
4

threejs-miniprogram

WeChat MiniProgram adapted version of Three.js
JavaScript
692
star
5

api-typings

Type definitions for APIs of Wechat Mini Program in TypeScript
TypeScript
673
star
6

computed

小程序自定义组件 computed / watch 扩展
TypeScript
654
star
7

miniprogram-simulate

小程序自定义组件测试工具集
JavaScript
487
star
8

kbone-ui

kbone-ui 是一套能同时支持 小程序(kbone) 和 vue 框架开发的多端 UI 库(PS:新版 kbone-ui 已出炉并迁移到 kbone 主仓库,此仓库仅做旧版维护之用)
Vue
439
star
9

sm-crypto

miniprogram sm crypto library
JavaScript
414
star
10

lottie-miniprogram

lottie for miniprogram
JavaScript
351
star
11

kbone-template-vue

a simple vue template for kbone
JavaScript
350
star
12

minigame-canvas-engine

轻量级canvas2d渲染引擎,开放数据域开发解决方案。
JavaScript
274
star
13

miniprogram-component-plus

JavaScript
253
star
14

miniprogram-custom-component

JavaScript
197
star
15

slide-view

weapp custom component -- slide-view
JavaScript
185
star
16

mobx-miniprogram-bindings

小程序的 MobX 绑定辅助库
TypeScript
175
star
17

glass-easel

Multiple-backend declarative component-based JavaScript framework
TypeScript
172
star
18

minigame-demo

微信小游戏组件 / API / 云开发示例
JavaScript
152
star
19

navigation-bar

weapp custom component -- navigation-bar
JavaScript
148
star
20

wxml-to-canvas

JavaScript
146
star
21

kbone-template-react

a simple react template for kbone
JavaScript
134
star
22

minigame-adaptor

C#
131
star
23

miniprogram-i18n

小程序国际化方案 / The internationalizational (i18n) library for wechat miniprogram
TypeScript
129
star
24

miniprogram-slim

JavaScript
123
star
25

h5-to-miniprogram

a simple tool for transforming h5 to miniprogam
JavaScript
113
star
26

minigame-api-typings

Type definitions for APIs of Wechat Mini Game in TypeScript
TypeScript
106
star
27

minigame-lockstep-demo

JavaScript
102
star
28

awesome-skyline

94
star
29

kbone-api

TypeScript
73
star
30

skylint

Skyline 小程序迁移工具. Migration assistant for Skyline miniapp.
TypeScript
69
star
31

miniprogram-cli

JavaScript
68
star
32

miniprogram-compat

微信小程序 js 执行环境的兼容信息
JavaScript
66
star
33

mpflow

TypeScript
61
star
34

miniprogram-api-promise

JavaScript
59
star
35

miniprogram-file-uploader

JavaScript
57
star
36

xr-frame-cli

Tools for xr-frame in wechat miniprogram.
TypeScript
50
star
37

kbone-template-kboneui

JavaScript
43
star
38

j-component

a mock minprogram component framework
JavaScript
43
star
39

miniprogram-gesture

微信小程序手势库
JavaScript
39
star
40

h5-to-miniprogram-demo

一个简单的使用 h5-to-miniprogram 工具进行 h5 页面转换成小程序的 demo
JavaScript
31
star
41

miniprogram-elder-transform

小程序适老化自动适配工具
TypeScript
31
star
42

miniprogram-barrage

JavaScript
23
star
43

minigame-tuanjie-transform-sdk

JavaScript
22
star
44

miniprogram-hooks

小程序自定义组件 hooks
JavaScript
20
star
45

miniprogram-cloudbase-meeting-demo

云开发直播运营活动 demo
JavaScript
17
star
46

kbone-template-preact

a simple preact template for kbone
JavaScript
12
star
47

miniprogram-game-quickstart

JavaScript
12
star
48

wechat-miniprogram.github.io

HTML
11
star
49

miniprogram-quickstart

JavaScript
10
star
50

gtktest

Flutter linux demo with webview.
C++
9
star
51

miniprogram-offline-demo

小程序弱网/离线 demo
JavaScript
9
star
52

miniprogram-data-panel

小程序数据面板组件
JavaScript
6
star
53

xnet-miniprogram

Python
6
star
54

router

JavaScript
4
star
55

babel-preset-miniprogram

微信小程序 babel 构建环境预设
JavaScript
2
star
56

minigame-playable

TypeScript
2
star
57

miniprogram-mock

mock api for miniprogram
JavaScript
1
star
58

mp-user-avatar

TypeScript
1
star