下拉刷新和上拉加載是業務上一個很常見的需求,在微信小程序裏,提供了下拉刷新的方法 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
選擇器獲得一個節點。請儘可能減小這些方法的調用頻率( 函數節流
)或 緩存結果