一、踩坑
最近产品一直想要在h5页面里加一个下拉刷新的功能,活来了就得干呀。
先是找了比较火的better-scroll,但是不尽人意呀,奈何页面交互太多,使用better-scroll反而带出了一堆bug
better-scroll禁止了原生的click事件,想要content可以click,需要在初始化的时候配置。我配置完之后,click事件都触发两次,bug不就来了吗,比如弹窗,点一次,事件触发两次,相当于没弹
看文档说嵌套的better-scroll才会派发两次click,我没嵌套呀。。。算了还得自己来
二、设计
首先梳理一下整个功能点,参考app中的下拉刷新。 有下拉动作,页面下移,不能无限下拉,有阈值,到了一定阈值就拉不动了。 松手后回弹,停留指定位置,出现加载动作,页面还原
- 监听touchstart事件,记录手指对应文档上边缘距离PageY
const handleTouchStart = useCallback(e => {
const [touches = {}] = e.changedTouches;
const { pageY } = touches;
setStartY(pageY);
}, []);
- 监听touchmove事件,当content scrollTop为0,并且此时differ = currPageY - startPageY,differ大于0时,说明时下拉动作,对应增加页面的translateY = differ,从而实现页面下移
const handleTouchMove = useCallback(e => {
const [touches] = e.changedTouches;
const { pageY } = touches;
if (viewRef?.current) {
const { scrollTop } = viewRef.current;
const differ = pageY - startY;
if (scrollTop === 0 && differ > 0) {
setTop(differ);
}
}
}, [startY]);
- 监听页面touchend事件,设置一个阈值,当下拉超过阈值,设置translateY = stop,执行回调函数,函数执行完成,设置translateY = 0,还原页面
const handleTouchEnd = useCallback(e => {
const [touches] = e.changedTouches;
const { pageY } = touches;
if (viewRef?.current) {
const { scrollTop } = viewRef.current;
const differ = pageY - startY;
if (scrollTop === 0 && differ > 20) { // 下拉超过阈值
setTop(stop);
setDynamic(true);
refresh().then(() => {
setTimeout(() => {
setTop(0);
setDynamic(false);
}, loadingTime);
}).catch(() => {
setTimeout(() => {
setTop(0);
setDynamic(false);
}, loadingTime);
});
} else {
setTop(0);
}
}
}, [stop, startY, loadingTime, refresh]);
三、实现
先看下效果
实际实现的时候做了一些改进:
- 下拉到阈值后,越拉页面下移得越小,值到拉不动,这里使用了log10函数计算。
- 增加loading时间,有时候刷新接口很快返回,loading效果刚出就结束了,会有闪一下的感觉
到这里基本就完成了,完整代码可以参考这里