下拉刷新和上拉加载是业务上一个很常见的需求,在微信小程序里,提供了下拉刷新的方法 onPullDownRefresh
。而实现上拉加载相对来讲就比较不方便了。git
虽然微信的官方文档有不少坑,但下拉刷新介绍的仍是很全面的。在这里稍稍带过。github
config
中的 window
配置 enablePullDownRefresh
.Page
中定义 onPullDownRefresh
钩子函数。到达下拉刷新条件后,该钩子函数执行,发起请求方法。wx.stopPullDownRefresh
中止下拉刷新。config = {
pages: [
'pages/index'
],
window: {
backgroundTextStyle: 'light',
navigationBarBackgroundColor: '#ccc',
navigationBarTitleText: 'WeChat',
navigationBarTextStyle: '#000',
enablePullDownRefresh: true
}
}复制代码
onPullDownRefresh() {
wepy.showNavigationBarLoading()
setTimeout(()=>{
this.getData = '数据拿到了'
wepy.stopPullDownRefresh()
wepy.hideNavigationBarLoading()
this.$apply()
},3000)
}复制代码
效果以下:
你会发现下拉的过程有些僵硬。这其实是没有添加背景色的缘由,加上背景色后再试试。
如今感受好多了吧。下拉刷新有现成的配置和方法,很容易实现,可上拉加载就不一样了。小程序
首先看一下要实现的效果,这是3g端的上拉加载。小程序要实现一样的效果。
首先功能有微信小程序
这里有两个实现的方案。一个是 page
自带的下拉触底钩子事件 onReachBottom
能作的只是下拉到底部的时候通知你触底了,一个是 scroll-view
标签自带事件。如今用两个方法分别实现一下上拉加载。浏览器
模板缓存
<template>
<view class="loading"></view>
<view class="container"
@touchmove="moveFn"
@touchstart="startFn"
@touchend="endFn"
style="transform:translate3d(0,{{childTop}}px,0)">
<repeat for="{{list}}"
key="index"
index="index"
item="item">
<view>{{ item }}<text>{{index}}</text></view>
</repeat>
</view>
</template>复制代码
钩子函数bash
data = {
getData: '',
top: 0,
lastTop: 0,
canDrag: false,
list: []
}
onReachBottom() {
this.canDrag = true
}
methods = {
moveFn(ev) {
let nowY = ev.changedTouches[0].clientY
nowY = nowY-this.lastTop
if(nowY > 0 )
this.canDrag = false
if( nowY<=0 && this.canDrag ) {
this.top = nowY
}
if( -this.top>= this.maxTop )
this.top = -this.maxTop
},
startFn(ev) {
this.lastTop = ev.changedTouches[0].clientY
},
endFn() {
if(this.top <= -this.maxTop) {
this.text = "去请求数据了"
setTimeout(()=>{
this.text = "请求回来了"
this.canDrag = false
this.list.push(...["数据","数据","数据"])
this.$apply()
this.top = 0;
return
},1000)
}
},
gotoTop() {
wepy.pageScrollTo({
scrollTop: 0
})
}
}复制代码
scroll-view: 可滚动视图区域。
它的具体用法不赘述,看官方文档就好了。这里提解决上述问题的方法便可。app
bindscrolltolower
类比原生全局钩子 onReachBottom
<scroll-view scroll-y
id="content"
@scroll="scroll"
@scrolltolower="lower"
scroll-top="{{gotoTopNum}}"
lower-threshold="100"
style="transform:translate3d(0,{{childTop}}px,0)">
<view class="sty-search"
@touchmove="moveContent"
@touchstart="startContent"
@touchend="endContent">...</view>
</scroll-view>复制代码
以上就是最终的模板,你可能在想为何这么复杂。虽然复杂,但每一个属性都是有用的,固然这其中有几个坑在等着咱们。
首先节点分为滚动容器和子容器。iphone
Q:为何滚动容器里嵌套一个子容器,而且将拖动的三个方法绑定在它上面。
A:这是第一个坑,由于 scroll-view
容器不能绑定 touchmove
事件,那若是绑定了会怎么样呢?不会怎么样,事件钩子不会调用。(这个坑在官方文档查不出来,当时绑定了不调用,在社区找到了解决方法,就是将touchmove事件绑定到子容器)
再来看代码
methods = {
async lower() {
this.canDrag = true
},
scroll (ev) {
this.scrollTop = ev.detail.scrollTop
if (ev.detail.deltaY > 0) {
this.canDrag = false
}
let nowSet = this.documentHeight+this.scrollTop-this.contentHeader
let num = Math.ceil(nowSet/this.listHeight) - 1
num = Math.floor(num / this.pageBean.pageSize) + 1
num = (num > this.pageBean.pageNo) ? this.pageBean.pageNo : num
if(num != this.page) {
this.page = num
this.$apply()
}
},
startContent(ev) {
this.lastTop = ev.changedTouches[0].clientY
if(!this.documentHeight){
this.documentHeight = wx.getSystemInfoSync().windowHeight
}
/* 这句是解决回到顶部的bug */
if (this.gotoTopNum || this.gotoTopNum==0) { this.gotoTopNum = undefined }
},
moveContent (ev) {
let {
pageNo,
pageSize,
totalCount
} = this.pageBean
let nowY = ev.changedTouches[0].clientY
nowY = nowY-this.lastTop
if (this.canDrag && nowY) {
this.state = 1;
if (nowY <= -this.maxMove) {
nowY = -this.maxMove
}
if (nowY <= 0) {
this.childTop = nowY
}
}
},
async endContent(ev) {
let {
pageNo,
pageSize,
totalCount
} = this.pageBean
if (this.childTop === -this.maxMove) {
/* 状态 */
if (pageNo >= this.maxPage || pageNo * pageSize >= totalCount) {
this.state = 0
} else {
this.pageBean.pageNo++
await this.fillData()
this.childTop = 0
this.canDrag = false
this.$apply()
}
}
/* 若是没超过刷新高度则重置 */
this.childTop = 0
},
gotoTop() {
this.gotoTopNum = 0
},
}
复制代码
Q: 为何要在 touchStart
的时候 将 gotoTopNum
置为 undefined
?
A: 由于这个页面有一个回到顶部的功能,当回到顶部时,gotoTopNum
置为0,再次下翻时,虽然实际的 scrollTop
改变了,可是 gotoTopNum
还为0,再次点击回到顶部时,由于数据未改变,视图层就不会去更新。因此在 touchStart
的时候给 gotoTopNum
一个无效的值,再次点击回到顶部时,视图层也就更新了。
对比 | 原生滚动 | scroll-view |
---|---|---|
性能 | 流畅 | 节点过多会明显卡顿 |
滚动函数 | onPageScroll | bindscroll |
回到顶部 | wepy.pageScrollTo(object) 默认有动画效果,且没法取消 | 设置节点属性 scroll-top |
坑点 | 暂时没有发现 | 1, 与 enablePullDownRefresh , ReachBottom 不能共存 2,不能绑定touchmove事件 3,不能触发双击bar栏回到顶部的“彩蛋” |
并无。
实现的上拉加载在模拟器上跑的很流畅,不存在问题。但是。
若是是苹果机的话(暂时测试iphone5 和 iPhone7),存在这样一个问题,上拉或下拉回弹效果,这个效果会影响上拉的距离。
这个问题想了好久,目前不能优雅的解决。
因此就找产品经理修改了需求,去掉了上拉动画效果 因此最终的效果就变成:
id
选择器获得一个节点。请尽可能减小这些方法的调用频率( 函数节流
)或 缓存结果