小程序页面部分下拉刷新解决方案

小程序要下拉刷新,有两种方式:

  1. 整个页面刷新
  2. 局部刷新
  • 整个页面刷新

整体刷新首先需要再页面配置文件(json)中添加配置:

"enablePullDownRefresh": true

添加配置后页面可以下拉,然后再js文件onPullDownRefresh中编写下拉刷新逻辑代码。注:处理完后需调用wx.stopPullDownRefresh()结束下拉刷新,否则真机上页面下拉后不会回到原来的位置。

  • 局部刷新

对于有些页面,如下图:

局部刷新列表

顶部是切换的导航条剩下的是列表,刷新的时候不需要带着导航一起下拉刷新。小程序提供了一个组件:scroll-view。我们只需要使用scroll-view将列表数据包裹起来就可以了。

  • refresher-enabled="true"开启下拉刷新
  • refresher-triggered="{{refresherTrigger}}"控制下拉刷新显示,在数据请求结束后应将refresherTrigger设置为false
  • bindrefresherrefresh="pullDownRefresh"在js文件pullDownRefresh函数中处理下拉刷新逻辑

对于局部刷新,当页面数据较少的时候,我们会遇到一个问题:

可以看到高度存在问题,scroll-view官方文档中有说:

可滚动视图区域。使用竖向滚动时,需要给scroll-view一个固定高度,通过 WXSS 设置 height。组件属性的长度单位默认为px,2.4.0起支持传入单位(rpx/px)。

  • 失败尝试

对于列表,高度是未知的。在WXML中写样式:style="height: 100vh;"尝试,对于数据少的问题解决了,但是数据多有分页的列表又出现了问题,无法加载下一页数据。那么,如果数据加载完后我们能知道页面有多少数据,就可以知道该用哪一个高度了。

解决办法:

使用自定义事件,当page等于1时,在组件中根据数据多少判断应使用100vh还是100%并返回单位:

this.triggerEvent('initHeight', {unit: data.length >= 10 ? '%' : 'vh'})

这个方案显示和下拉会出现问题。

  • 最终方案
  1. 在页面配置文件中添加禁用页面滚动。如果这里不禁用滚动是属于页面的,而非scroll-view的。
"disableScroll": true
  1. scroll-view加上一个id属性class等也行,完整如下:
<scroll-view id="scrollList" refresher-enabled="true" scroll-y="true" enable-back-to-top="true" refresher-triggered="{{refresherTrigger}}" bindscrolltolower="reachBottom" bindrefresherrefresh="pulldownRefresh" style="height: {{scrollHeight}};">
// 其他页面代码...
</scroll-view>
  1. 使用this.createSelectorQuery()查询scroll-view节点,用屏幕高度减去scroll-view距离顶部的高度,得到该元素所占高度。这样scroll-view刚好铺满页面。如果你的scroll-view只是在页面中间的一部分,那还需要减去底部距离。
const systemInfo = wx.getSystemInfoSync();
const query = this.createSelectorQuery();
query.select('#scrollList').boundingClientRect(rect => {
    if(rect !== null) {
        this.setData({
            scrollHeight: `${systemInfo.windowHeight - rect.top}px`
        })
    }
}).exec()

实际项目中,由于很多页面都会用到这段代码,可以将其封装到behavior里面,其他页面直接调用便可。

module.exports = Behavior({
    data: {
        scrollHeight: '100vh'
    },
    methods: {
        initScrollHeight: function(selector = '#dataList') {
            const systemInfo = wx.getSystemInfoSync();
            const query = wx.createSelectorQuery().in(this);
            query.select(selector).boundingClientRect(rect => {
                if(rect !== null) {
                    this.setData({
                        scrollHeight: `${systemInfo.windowHeight - rect.top}px`
                    })
                }
            }).exec()
        }
    }
})

注意:在真机上,部分机型有些列表最后一条数据可能被tabbar遮挡,这样的单独处理,在样式中添加一个距离底部的边距即可。