微信小程序 自定义刷新实现
关于为什么会使用 自定义刷新?
- 自定义头部导航栏下拉刷新不会固定 (
安卓异常
ios正常 ). - 下拉刷新三个点的位置 是根据自定义头部来的 用户需要
下拉较长
距离 才能看到三个点. - UI 样式问题.
效果图
最终效果跟下方是一样的上面没动图......
思路分析
- 在页面顶部放置一个view,这个view主要用来展示刷新状态提示用户,view初始高度为0
- 监听用户手指touch事件,根据用户移动的距离来动态改变顶部刷新状态view的高度
- 设置一个高度阈值,当下拉距离大于等于这个阈值,松开手指触发刷新操作
组件实现
index.wxml
<!-- wxml布局文件 -->
<scroll-view style='height:100%' scroll-y='{{!isindrag}}' bindscroll='scorll'>
<!-- 监听布局touch事件 touchstart 手指触摸动作开始
touchend 手指触摸动作结束
touchmove 手指触摸后移动 -->
<view class='column' bindtouchstart='start' bindtouchend='end' bindtouchmove='move'>
<!-- //刷新状态view -->
<view style='height:{{viewHeight}}px;margin-top: {{marginTop}}px;padding-top: {{paddingTop}}px;' class='refresh'>
<image wx:if="{{!RefreshStatus&&isindrag}}" class="sunshine" src="../../assets/taiyang.png"></image>
<image wx:if="{{!RefreshStatus&&isindrag}}" class="cloud" src="../../assets/yun.png"></image>
<view wx:if="{{RefreshStatus}}" class="sunshineText"> {{desc}}</view>
</view>
<slot></slot>
</view>
</scroll-view>
paddingTop 参数
有的页面多了个Tab 标签页所以要加上这个高度 否则标签会覆盖 展示位置会有问题
index.js
var sy; //记录手指的y坐标
Component({
properties: {
// 自定义文案
text: {
type: String,
value: '记录已更新'
},
// 滚动条距离顶部的距离 用户如果上拉滚动底部后,在下拉往上的时候,会一直派发父组件的事件.
// 这个参数的用处就在于滚动条的高度如果大于100 下拉就不让他派发事件调用接口了.
// 其实本身咱们用的 scroll-view bindscroll='scorll'事件.
// 是可以拿到滚动条位置的.但是必须有固定高度... 然后才有这个参数.
// 通过父组件的page页 调用onPageScroll事件时时传送当前滚动条的位置.(下方有例子 )
TopVal: {
type: [String, Number],
value: 0
},
//上方 有关于这个参数的图例
paddingTop:{
type: [String, Number],
value: 0
}
},
data: {
desc: '', //刷新提示语
// desc: '下拉刷新', //刷新提示语
viewHeight: 0, //刷新view高度阈值
scrolltop: 0, //scorll-view滑动离顶部的距离
isindrag: false, //是否在下拉状态(必须要滑动到顶部才能触发)
RefreshStatus: false //是否刷新完成
},
methods: {
start(e) {
//记录手指触摸是的y坐标
console.log(e);
sy = e.touches[0].clientY;
console.log('开始触摸 sy : ' + sy + ' scrolltop : ' + this.data.scrolltop)
},
move(e) {
//计算手指滑动的距离
var delta = e.touches[0].clientY - sy;
console.log('delta : ' + delta)
//scorll-view滑动到顶部且继续向上滑动时,走scorll-view滑动流程
if (this.data.viewHeight <= 0 && delta <= 0) {
return;
}
//scorll-view已经滑动到顶部,继续下拉进入下拉状态
if (this.data.scrolltop <= 0) {
if (this.data.isindrag == false) {
this.setData({
isindrag: true
})
}
var tempdelta = 0;
console.log('viewHeight : ' + this.data.viewHeight)
if (delta > 0) { //手指向下滑动
if (this.data.viewHeight > 70) { //触发阈值,更改状态
// this.setData({
// desc: '松开刷新'
// })
tempdelta = this.data.viewHeight + delta / (this.data.viewHeight - 70) //增大下拉阻尼感
} else {
// this.setData({
// desc: '下拉刷新'
// })
//手指移动未到阈值,按正常滑动增加高度
tempdelta = this.data.viewHeight + delta
}
} else { //手指向上滑动
tempdelta = this.data.viewHeight + delta
//刷新状态view最小为0
if (tempdelta <= 0) {
tempdelta = 0;
}
// this.setData({
// desc: '下拉刷新'
// })
}
//滑动完成设置刷新view高度
if (!this.data.RefreshStatus) {
this.setData({
// viewHeight: tempdelta
})
}
}
//每次滑动事件后记录y坐标
sy = e.touches[0].clientY;
},
end(e) {
console.log('手指离开')
var that = this;
console.log(this.data.TopVal);
//手指离开时,如果阈值大于等于70,则触发刷新
if (this.data.viewHeight >= 70 & this.data.TopVal < 100) {
that.setData({
// desc: '正在刷新...',
viewHeight: 70,
})
//模拟耗时操作,2秒后恢复正常状态
// setTimeout(function () {
// sy = 0
// that.setData({
// desc: '下拉刷新',
// hei: 0,
// isindrag: false,
// scrolltop: 0
// })
// }, 2000)
//离开后触发 父组件相应接口事件
this.triggerEvent('endEvent');
} else {
//未下拉到阈值,松开时则收起刷新view
sy = 0;
that.setData({
// desc: '下拉刷新',
viewHeight: 0,
isindrag: false,
scrolltop: 0,
RefreshStatus:false
})
}
},
//父组件触发事件 (显示文案后,2秒后再次调用下面 FiveMillisecondsLater 方法 彻底关闭)
closeGold() {
sy = 0;
this.setData({
// desc: '记录已更新',
desc: this.data.text,
RefreshStatus: true,
viewHeight: 32,
})
},
FiveMillisecondsLater() {
this.setData({
// desc: '下拉刷新',
viewHeight: 0,
isindrag: false,
scrolltop: 0,
RefreshStatus: false
})
},
//这个事件未触发 原因:没有固定高度! 上方有其他获取滚动条的方案。如果有固定高度可以不用TopVal参数!!!!!!
scorll(e) {
//未进入下拉状态时,记录scorll-view滑动距离顶部的距离
var st = e.detail.scrollTop;
console.log('滚动 st : ' + st)
if (this.data.isindrag == false) {
this.setData({
scrolltop: st
})
}
},
}
})
index.json
{
"component": true
}
index.wxss
.refresh {
background: #F7F7F7;
position: relative;
}
.sunshine {
width: 76rpx;
height: 76rpx;
position: absolute;
z-index: 2;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-50%);
}
.cloud {
width: 242rpx;
height: 56rpx;
position: absolute;
z-index: 1;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-50%);
}
.sunshineText {
text-align: center;
height: 64rpx;
line-height: 64rpx;
background: #E3F8EE;
font-size: 28rpx;
font-family: 'PingFang SC-Regular, PingFang SC';
font-weight: 400;
color: #28C87A;
}
组件使用
endEvent 子组件抛出的事件
使用时 需要把小程序默认的刷新事件关闭 ( "enablePullDownRefresh": false )
app.json "usingComponents" 对象引入组件
<scrollReflash bindendEvent="endEvent" TopVal="{{TopVal}}" text="记录已更新" id="scrollReflash"
paddingTop='55'>
<view>
我是测试列表
我是测试列表
我是测试列表
我是测试列表
</view>
</scrollReflash>
//方法调用
endEvent() {
this.getDetailById(true)
},
//小程序获取滚动条高度
onPageScroll: function (e) {
this.setData({
TopVal: e.scrollTop,
})
},
//派发事件调用下拉刷新接口
getDetailById(show) {
let countDown = this.selectComponent('#scrollReflash'); // 页面获取自定义组件实例
if (show) {
countDown.closeGold(); // 通过实例调用组件事件
}
setTimeout(() => {
countDown.FiveMillisecondsLater(); // 通过实例调用组件事件
}, 2000);
},
]()
遇到的问题
暂时也没有好的方案. 所以只能父传给子组件 .
亲测可用 有问题滴滴🙂
转载自:https://juejin.cn/post/7231385783181983805