微信小程序仿Material Design风格的下拉刷新组件

前言
最近一段时间在研究微信小程序的开发,相比于原生app来说,确实上手要容易不少,也能够提升项目的开发速度。但与此同时,小程序开发中也存在一些“坑”需要我们注意,因此我想记录一下自己在微信小程序开发中遇到的一些问题,方便日后查阅。

在微信小程序开发中实现下拉刷新最简单的方式就是在页面对应的json文件中添加enablePullDownRefresh:true,然后在Page.onPullDownRefresh 方法中执行刷新逻辑。这种方式有一些局限性,一是无法自定义下拉刷新效果,只能使用默认的“三个圆点”样式;二是下拉刷新的视图位置是固定在顶部的,如果要刷新的视图元素不是位于页面顶部,那么使用这种方式就不太好了,最常见的场景就是顶部Tab标签栏,下面是要刷新的列表。在小程序基础库版本2.10.1之后,scroll-view支持自定义下拉刷新了,很好地解决了上述的两个问题,缺点当然就是兼容性了。于是想着自己实现一个下拉刷新组件,由于我本身是做Android开发的,所以尝试实现了一个仿Material Design风格的下拉刷新效果(Android中的SwipeRefeshLayout),先附上一张效果图:

虽然没能做到百分之百的还原,不过基本功能还是实现了的。相关代码我已经上传到了github

使用方式

将组件拷贝到项目中,在页面的json文件中引入,这里就不展示了。组件可设置的属性如下:

属性 类型 默认值 说明
color string black 下拉刷新进度条颜色,默认值为黑色
backgroundColor string white 下拉刷新圆圈背景颜色,默认值为白色
threshold number 20 下拉刷新阈值(单位px),下拉距离超过该值时触发刷新
loadMoreEnable boolean false 是否开启上拉加载
bindrefresh eventhandle 下拉刷新回调函数
bindloadmore eventhandle 上拉加载回调函数

此外,组件还定义了一个setRefresh()函数,用于设置刷新状态,参数传入一个布尔值,true表示开始刷新,显示下拉刷新圆圈;false表示结束刷新,隐藏下拉刷新圆圈。
示例代码如下:
index.wxml

<swipe-refresh-layout id='refresh' style='width:100vw;height:200rpx;' loadMoreEnable bindrefresh='refresh' bindloadmore='loadMore'>
  <!-- 要刷新的内容 -->
</swipe-refresh-layout>

index.js

Page({

  /**
   * 页面的初始数据
   */
  data: {},

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function(options) {
    this.swipeRefresh = this.selectComponent('#refresh');
  },

  /**
   * 下拉刷新
   */
  refresh: function() {
    // 模拟获取数据
    setTimeout(() => {
      // 结束下拉刷新
      this.swipeRefresh.setRefresh(false);
    }, 3000);
  },

  /**
   * 上拉加载
   */
  loadMore: function() {
    // ...
  }
})

需要注意,使用时必须给swipe-refresh-layout组件一个固定的宽度和高度

实现原理

实现原理还是比较简单的,大体上就是通过监听触摸事件,在touchstart事件回调中记录手指按下的坐标;在touchmove事件回调中计算手指在竖直方向上的滑动距离,通过css的transform属性实现下拉刷新圆圈的移动;在touchend事件回调中计算手指抬起时的滑动距离,如果向下的滑动距离超过阈值就触发下拉刷新事件,否则将下拉刷新圆圈归位。由于在滑动的过程中需要频繁地进行用户交互,出于性能方面的考虑,我使用了WXS函数用来响应触摸事件,将事件定义在视图层,解决视图层和逻辑层间通信耗时的问题。
虽然整体的实现逻辑不难理解,但是在开发过程中我还是遇到了几个问题,这里简单介绍一下。

  • touchmove导致的卡顿问题

一开始我使用的是bindtouchmove属性监听手指滑动事件,在开发工具上测试时没有什么问题,后来运行在安卓真机上才发现手指触摸屏幕下拉时刷新圆圈的移动比较卡顿,不流畅。在微信开放社区查了一下这个问题,发现也有人遇到过,目前的解决方案就是将bindtouchmove改为catchtouchmove。具体原因还不清楚,可能是官方的bug吧,又或者小程序本身就是这样设计的。改为catchtouchmove后确实是解决了下拉卡顿的问题,但是同时会导致页面内容无法滑动,如何解决这个问题呢,我们不妨考虑一下具体的使用场景,正常情况下只有在页面内容处于顶部时才可以下拉刷新,可以利用这个条件来判断是否需要我们自己处理touchmove事件。具体的做法是这样的,首先在组件最外层使用scroll-view,通过bindscroll监听滑动事件:

_scroll: function(e) {
  if (e.detail.scrollTop <= 50) {
    // 滚动到顶部
    this.setData({
      scrollTop: true
    });
  } else {
    this.setData({
      scrollTop: false
    });
  }
}

使用一个变量scrollTop来记录是否滑动到了顶部,这里的判断条件为什么是e.detail.scrollTop <= 50而不是e.detail.scrollTop <= 0呢,因为通过测试我发现有时页面滑动到顶部时e.detail.scrollTop的值并不是0,而是一个接近0的整数,为了保证每次页面滑动到顶部都能改变scrollTop的状态,这里就给了一个默认值,取50是因为官方文档上给出的默认阈值就是50。

之后在catchtouchmove回调函数中根据scrollTop的值判断是否需要处理滑动事件,如果scrollTop的值为false(页面内容不处位于顶部)就直接return。

touchmove: function(e) {
  if (!this.data.scrollTop) {
    return;
  }
  // 处理滑动事件
  
}

这样就解决了页面内容始终无法滚动的问题,当然上面的代码只是简单地说明解决方法,详细内容可以参考组件的源码。

  • 下拉刷新圆圈的显示层级问题

正常情况下下拉刷新圆圈是位于要刷新的内容之上的,并且不会随着内容的滑动而移动,我们很容易就想到使用position:fixed属性,通过z-index属性来设置元素的层叠顺序。但是如果下拉刷新圆圈的z-index指定一个大于0的数,而刷新组件又不是位于页面的顶部,就会导致下拉刷新圆圈始终会显示出来,如下图所示:

我这里采取的解决方案就是将下拉刷新圆圈的z-index指定为-1,而刷新内容的z-index指定为-2(取值不是固定的,只要比下拉刷新圆圈的小就可以),这样就可以解决下拉刷新圆圈覆盖在页面普通视图之上的问题。当然我的解决方案可能不是最好的,或者存在一些问题,如果大家有自己的想法欢迎提出,一起交流。

总结

目前我对于微信小程序的研究还比较浅显,对于CSS属性的运用也不是很熟练,可能组件本身还存在一些问题,或者大家还有更好的实现方案,欢迎提出。
最后附上Demo地址,大家可以进行参考。

参考文章

极致的scroll-view的下拉刷新扩展组件

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容