最近在用uniapp写小程序时接到了一个需求,下滑刷新跳转,写好之后大概如下图。
可以看出,这个功能其实和小程序自带的下拉刷新非常像,但它是到底部才能继续上滑加载,作者在uniapp的社区也寻找了一段时间的插件,但没有找到很符合的,在网上进行搜索也是大片的基础触底加载下拉刷新之类的文章,所以决定自己手搓一个,故有此文。
首先来分析一下我们该怎么做,既然是上滑,那就势必要监听用户的滑动操作,这点uniapp有提供事件,我们只需要把他们绑定在父元素上就好,我这里是绑定到了最大的父元素上。
<view class="read" @touchstart="start" @touchend="end" @touchmove="move">
这三个事件分别是用户手指触碰屏幕,在屏幕上滑动,以及离开屏幕的事件,他们都会携带一下信息,比如我们需要的坐标信息。
拿到这些信息之后,就可以将他们先存起来,方便后面分析。(这里用的是vue2)
touches: {
startY: 0, //起始Y轴坐标
moveY: 0, //移动过程Y轴坐标
refreshHeight: 0, //下拉刷新的距离 用于赋值到translate rpx
refreshTargetHeight: 300, //下拉刷新的目标值 rpx
maxRefreshHeight: 300 //最大下拉距离 包括减缓距离 rpx
}
然后是几个滑动的事件函数和一个判断是否是上滑手势的函数
methods: {
//判断是否为下拉手势
isPullDown() {
let {
startY,
moveY
} = this.touches
if (moveY < startY) {
return true
}
return false
},
start(e) {
this.touches.startY = e.touches[0].pageY
},
move(e) {
let {
refreshHeight,
refreshTargetHeight,
maxRefreshHeight
} = this.touches
//超出最大边界值 跳出
if (refreshHeight >= maxRefreshHeight) return;
// 记录移动过程中的 Y 轴坐标
this.touches.moveY = e.touches[0].pageY
let {
startY,
moveY
} = this.touches
//计算下拉差值
let distance = startY - moveY
//到达目标值后 下拉距离减缓
if (refreshHeight >= refreshTargetHeight) {
this.touches.refreshHeight = refreshHeight + (distance - refreshHeight) / 10
return
}
//符合下拉 动态赋值translate
if (this.isPullDown()) {
this.touches.refreshHeight = distance
}
},
async end(e) {
if (!(this.is_down && (this.is_novel_end || this.ai_data.length > 7))) return
if (this.isPullDown()) {
let {
refreshHeight,
refreshTargetHeight
} = this.touches
//未到达目标值
if (refreshHeight < refreshTargetHeight) {
this.touches.refreshHeight = 0
console.log('未到达目标值 回弹')
return
}
//模拟加载数据
console.log('加载数据中...')
// await (你要执行的操作)
this.touches.refreshHeight = 0
}
},
}
这样js的部分差不多就写完了,接下来是滑动时页面和底部加载区域的位移效果。
首先制作一个底部的加载区域。
<view class="top_refresh">
<uni-icons type="spinner-cycle" size="60"></uni-icons>
<text>继续上滑,开启新冒险~</text>
</view>
然后使用fixed绝对定位将它定位在底部,再用transform把它移出屏幕外。
.top_refresh {
position: fixed;
left: 0;
padding-bottom: 130rpx;
transform: translateY(160rpx);
height: 300rpx;
width: 100vw;
background-color: rgba(244, 249, 246);
}
接下来是位移效果,首先是在你希望在滑动时产生位移效果的元素上添加
<view class="read_content" id="read_content" :style="{transform:'translateY(' + -touches.refreshHeight + 'rpx);'}">
然后是在底部加载区域上添加,
<view class="top_refresh" :style="{bottom: (touches.refreshHeight/1.5) + 'rpx'}">
<uni-icons type="spinner-cycle" size="60"></uni-icons>
<text>继续上滑,开启新冒险~</text>
</view>
这样大体就完成了,但是我这里出了一个小问题,我的页面是不断向下加载的,只有加载完毕才应该开启上滑刷新,同时在页面高度很高的情况下,应该到达底部才能开启上滑刷新,这里因为是uniapp,无法获取DOM,可以通过uni.createSelectorQuery()来获取元素节点,同时通过onPageScroll监听页面的滑动,这两个api详见uniapp官方文档。
onPageScroll(res) {
const query = uni.createSelectorQuery().in(this);
query.select('#read_content').boundingClientRect(data => {
this.is_down = data.height + data.top > 800 ? false : true
}).exec();
}
然后通过节点的top值和height值判断是否到了底部,这里我很粗糙的写了一个800作为判断依据,实际上应该是手机的视口高度,然后用this.is_down来接收到结果,如果is_down值不为true,并且页面数据没有加载完毕时就不执行监听用户滑动的事件,也就是在三个事件中加上:
if (!(this.is_down && this.loading)) return
至此这个小功能就制作完毕了,新手第一次发文,如有不足,感谢斧正。