自定义实现H5页面下拉刷新功能
扫描二维码随身看资讯
使用手机 二维码应用 扫描右侧二维码,您可以
1. 在手机上细细品读~
2. 分享给您的微信好友或朋友圈~
前段时间我在进行小程序到H5的迁移,其中小程序中的下拉刷新功能引起了产品的关注。产品提到,我们迁移后的H5页面为何没有下拉刷新功能,于是我急忙着手解决这个问题。
最初我计划使用成熟的组件库来实现下拉刷新,但尝试后发现这些组件与我们H5页面的其他逻辑存在冲突(H5页面还有吸顶、锚点、滑动高亮、横向滚动)。由于H5页面上承载了太多功能,兼容性非常麻烦。考虑到下拉刷新功能并不复杂,我决定自己动手写一个。
流程图示
正常数据展示状态 --> 手指触摸屏幕下拉 --> 手指松开 --> 数据获取 --> 恢复正常数据展示状态
功能梳理
要实现这个功能,主要分为两部分。
监听手指触摸事件
通过监听事件,我们可以得知以下数据:
- 手指滑动的时机(手指开始触摸,结束触摸时间)
- 滑动方向(是横向滑动还是纵向滑动)
- 操作轨迹(手指操作从下往上还是从上往下滑动)
- 是否首屏(如果非首屏进行滑动时是正常滑动操作)。只有在 向下滑动 、 首屏 、 非加载状态 、 纵向滚动 并且有高度时,才能进行上述刷新流程。
css 和 提示文案
- 手指按住屏幕 由上往下滑动 未松开时,展示滑动的高度和提示 【释放刷新】 文案
- 手指松开后 高度回弹 ,显示 【数据更新中】 文案
- 数据请求接口成功后,显示 【更新成功】 文案,loading 内容和图标缓缓消失
具体实现
触摸的步骤可以分为: 手指按下(开始触摸)、手指移动不离开屏幕(触摸中)、手指离开屏幕(触摸结束),正好对应着三个 js 原生事件, touchstart 、 touchmove 和 touchend 。
触摸事件执行时机
touchstart 和 touchmove 在一次触摸流程只会执行一次,标志着开始和结束,但是 touchmove 不一样,只要手指还在屏幕上滑动没有松开,就会一直执行。如下图的输出的执行次数一样。
下拉元素绑定
首先需要给需要设置下拉刷新的区域绑定上这些事件。对于我们业务场景来说,头部区域无论如何操作,都需要保留展示的,那么我们只需要将事件绑定到下方开始显示下拉刷新的区域。
// html元素
<div className="refreshWrap">
{/* 下拉时文字提示 */}
<div className={`pullDownContent`} style={{ height: pullDownHeight }}>
{loading ? "" : "释放刷新"}
</div>
{/* 加载时动画 */}
<div className={`loadingFlex ${loading ? "" : "loadingHidden"}`}>
<div className="flexCenter">
<div className="loadingRing" />
<div className="loadingText">
{loading ? "数据更新中..." : "更新成功"}
</div>
</div>
</div>
<div className="middleArea">刷新区域下方内容区域</div>
</div>
// js 绑定
const pullDownClassName = ".refreshWrap";
bindPullDown() {
const pulldownElement = document.querySelector(pullDownClassName);
pulldownElement.addEventListener("touchstart", this.bindTouchstart);
pulldownElement.addEventListener("touchmove", this.bindTouchMove);
pulldownElement.addEventListener("touchend", this.bindTouched);
}
触摸开始
手指触摸到屏幕的逻辑非常简单,使用 startTouch 对象来记录触摸的位置,包含 x 、y 轴。
bindTouchstart = (event) => {
this.startTouch = event.touches[0];
};
触摸中
用户触摸中需要给他一个反馈,随着下拉的距离,屏幕上圈出的下拉区域会随之变大(下拉展示的区域会设置一个最大高度,如果能无限扩大展示不好看)。
用 endTouch 来保存触摸中的坐标值,因为触摸中的事件会执行多次,所以endTouch也会不断的更新,用来更新下拉时滑动的高度。
bindTouchMove = (event) => {
const { loading } = this.state;
this.endTouch = event.touches[0];
if (!loading && this.isInOneScreenPull() && this.isVerticalSliding()) {
const pullDownHeight = this.getPullDownHeight();
this.setState({
pullDownHeight,
});
}
};
根据endTouch的值可以判断出滑动距离、横向还是纵向滑动,滑动的高度、再获取滑动元素是否在首屏。
// 判断滑动的距离
calcDeltaY = () => Math.abs(this.endTouch.pageY - this.startTouch.pageY);
// 判断是否纵向滚动
isVerticalSliding = () => {
const deltaY = this.calcDeltaY();
const deltaX = Math.abs(this.endTouch.pageX - this.startTouch.pageX);
if (deltaY > deltaX && deltaY > 50) return true;
};
// 下拉展示高度最多展示为100,不能让加载区域无限制的扩大
getPullDownHeight = () => {
const deltaY = this.calcDeltaY();
return Math.min(deltaY, 100);
};
// 是否在首屏
isInOneScreenPull() {
const pulldownElement = document.querySelector(pullDownClassName);
return pulldownElement.scrollTop <= 0;
}
触摸结束
触摸结束时,将pulldownHeight设置为0,异步加载数据,加载数据时设置变量loading表示开始更新、结束更新,防止不停的下拉刷新调用接口。
bindTouched = (e) => {
const { loading, pullDownHeight } = this.state;
// 首屏、非加载状态、纵向滚动有高度时
if (!loading && pullDownHeight) {
this.setState({
pullDownHeight: 0,
});
this.getData();
// 重置触摸Y轴坐标点
this.startTouch = {};
this.endTouch = {};
}
};
平滑过渡动画
当下拉高度发生变化时,直接修改高度效果会比较生硬,使用css transition 属性进行平滑过渡、 animation 设置动画缓慢进入/消失。
.pullDownContent {
display: flex;
align-items: flex-end;
justify-content: center;
font-Size: 12px;
color: rgba(0, 0, 0, 0.25);
margin: auto;
transition: height 0.3s ease-out; /* 平滑过渡效果 */
overflow: hidden;
}
.loadingHidden {
animation: shrinkHeight 1s forwards;
}
@keyframes shrinkHeight {
100% {
height: 0;
opacity: 0;
overflow: hidden;
}
}
完整代码
以上便是滑动触发、高度提示、数据刷新的下拉刷新功能解析,完整代码我放在了GitHub上,戳drop-down-refresh可查看,欢迎大家点个star~
- LeetCode
- 天道模拟
- Quizlet官方版
- 巴士之星正式版
- 凯蒂塔防
- 僵尸乱斗土豆射击
- 地上铁最新版
- 金属风暴手游最新版
- 森林逃离伦蒂克
- 我的世界使命战区
- 天道只手遮天
- 女神联盟2单机版下载 v2.0.0.0 安卓版
- 创魔破解版无限点券最新版 v1.0.0690 安卓版
- 大征服者2战国时代无限金币版下载 v1.5.2 安卓版
- 高级前端开发需要知道的 25 个 JavaScript 单行代码
- MyBatis 的缓存机制
- 解决Docker镜像下载问题的Java工具
- Lakehouse 还是 Warehouse?(2/2).md
- C#进程调用FFmpeg操作音视频
- TiKV 源码分析之 PointGet
- 讯飞有一个可以根据描述文本自动生成PPT的AI接口,有趣
- 解决el-upload上传多张图片报错ERR_UPLOAD_FILE_CHANGED的问题
- 从零开始写 Docker(十八)---容器网络实现(下):为容器插上”网线“
- 开源.NET绘图库OxyPlot的跨平台应用
- AlertManager解析:构建高效告警系统
- 如何优化SparkSQL的monaco-editor语言服务
- 1
加查之花 正版
- 2
爪女孩 最新版
- 3
企鹅岛 官方正版中文版
- 4
捕鱼大世界 无限金币版
- 5
情商天花板 2024最新版
- 6
内蒙打大a真人版
- 7
烦人的村民 手机版
- 8
跳跃之王手游
- 9
球球英雄 手游
- 10
蛋仔派对 国服版本