前段时间在做小程序到H5的迁移,其中小程序中下拉刷新的功能引起了产品的注意。他说到,哎,我们迁移后的H5页面怎么没有下拉刷新,于是乎,我就急忙将这部分的内容给填上。

本来是计划使用成熟的组件库来实现,尝试之后发现这些组件和我们H5页面的其他逻辑有冲突(H5还有吸顶、锚点、滑动高亮、横向滚动),小小H5页面上承载了太多的功能,兼容起来非常麻烦,想着下拉刷新功能也不复杂,干脆我自己写一个好了。

流程图示

正常数据展示状态 --> 手指触摸屏幕下拉 --> 手指松开 --> 数据获取 --> 恢复正常数据展示状态

功能梳理

要实现这个功能,主要分为两部分。

监听手指触摸事件

通过监听事件,我们可以得知以下的数据

  • 手指滑动的时机(手指开始触摸,结束触摸时间)
  • 滑动方向(是横向滑动还是纵向滑动)
  • 操作轨迹(手指操作从下往上还是从上往下滑动)
  • 是否首屏(如果非首屏进行滑动时是正常滑动操作)

    只有在向下滑动首屏非加载状态纵向滚动并且有高度时,才能进行上述刷新流程。

css 和 提示文案

  • 手指按住屏幕由上往下滑动未松开时,展示滑动的高度和提示【释放刷新】文案
  • 手指松开后高度回弹,显示【数据更新中】文案
  • 数据请求接口成功后,显示【更新成功】文案,loading 内容和图标缓缓消失

具体实现

触摸的步骤可以分为: 手指按下(开始触摸)、手指移动不离开屏幕(触摸中)、手指离开屏幕(触摸结束),正好对应着三个 js 原生事件,touchstarttouchmovetouchend

触摸事件执行时机

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~

轻松实现H5页面下拉刷新:滑动触发、高度提示与数据刷新全攻略的更多相关文章

  1. H5页面下拉加载更多(实用版)

    近期在做一个H5网站,需要下拉加载更多产品列表的功能.百度搜索了好久,什么说法都有,什么插件都有.   醉了.基本上每一个能直接拿来用的. 最后发现: 1.dropload.js 插件  还可以,但是 ...

  2. H5 页面下拉加载更多

    1.html页面: <body onload="index_roll()"> ... </body> 2.js <script type=" ...

  3. ios系统微信浏览器、safari浏览器中h5页面上拉下滑导致悬浮层脱离窗口的解决方法

    一. 运行环境: iphone所有机型的qq浏览器,safari浏览器,微信内置浏览器(qq浏览器内核)等. 二. 异常现象: 1. 大幅度上下滑动h5页面,然后停止滑动,有时候会影响到页面滚动,如局 ...

  4. 刷新各ifream当前页,下拉项改变触发事件js,给选中项加背景色js

    <script type="text/javascript" language="javascript"> //刷新框架各页面 function r ...

  5. 微信小程序 禁止ios页面下拉下滑滚动 出现空白的情况

    项目需要做了一个图片拖动指定组件上删除,和排序的功能android测试正常, ios会出现拖动图片页面也跟着下滑的尴尬情况. 查文档下拉刷新配置默认是关闭的,后经查找文档发现在本页面page.json ...

  6. 页面滚动动态加载数据,页面下拉自动加载内容 jquery

    <!DOCTYPE=html> <html> <head> < script src="js/jquery.js" type=" ...

  7. Jquery页面滚动动态加载数据,页面下拉自动加载内容

    <!DOCTYPE=html> <html> <head> <script src="js/jquery.js" type="t ...

  8. 微信h5页面下拉露出网页来源的解决办法

    微信h5页面下拉露出网页来源的解决办法:将document的touchmove事件禁止掉 //禁止页面拖动 document.addEventListener('touchmove', functio ...

  9. LayUI中select下拉框选中触发事件

    代码: var form = layui.form, layer = layui.layer; // 监听 $(document).ready(function() { // select下拉框选中触 ...

  10. H5 移动调试全攻略

    H5 移动调试全攻略 随着移动设备的高速发展,H5 开发也成为了 F2E 不可或缺的能力.而移动开发的重中之重就是掌握调试技巧,定 Bug于无形. 一.概要 因为移动端操作系统分为 iOS 和 And ...

随机推荐

  1. [FAQ] FinalCutPro 竖版视频 加模糊背景变 横版视频

    把一段影片拖到时间轴上面,注意自定义尺寸选择 1920 x 1080,因为竖版的是 1080 x 1920. 切换到仅视频,并选择变形,视频区左右拖动视频到最大. 设置模糊效果为高斯曲线. 切回到全部 ...

  2. DE10-Lite加速度计使用教程

    DE10-Lite加速度计使用教程 1. 概述 DE10-Lite实验板上有一片5轴加速度计芯片ADXL345(通常称为G-sensor).它可以用来测量板子的倾斜角度.本文讲述如何以50次/秒的速度 ...

  3. 007_Orcad运用Excel表格创建复杂元器件

    007_Orcad运用Excel表格创建复杂元器件 以AD9135为例,有88个引脚,如果一个一个输入引脚名,比较慢.用Excel做出引脚列表,比较快捷. 首先需要查询datasheet,用Solid ...

  4. computed计算属性和watch的区别:

    计算 ' 单价 x 数量 = 总价 ' watch:就不写了,没意思 computed: computed:{ allPrice:function(){ return this.price*this. ...

  5. 通俗易懂的生产环境Web应用架构介绍

    前言 看见一篇非常通俗易懂且适合新手阅读的Web应用架构文章,我将其手工翻译了出来,分享给大家. 也可以去阅读英文原文,标题为,贴出链接: https://stephenmann.io/post/wh ...

  6. 2024-05-01:用go语言,给定两个长度为偶数n的整数数组nums1和nums2, 分别移除它们各自的一半元素, 将剩下的元素合并成集合s。 找出集合s中可能包含的最多元素数量。 输入:nums

    2024-05-01:用go语言,给定两个长度为偶数n的整数数组nums1和nums2, 分别移除它们各自的一半元素, 将剩下的元素合并成集合s. 找出集合s中可能包含的最多元素数量. 输入:nums ...

  7. docker-compse 安装nginx 配置目录挂载

    一.新建一个启动服务的目录 mkdir /usr/local/docker/compose cd /usr/local/docker/compose 二.新建文件docker-compose.yml ...

  8. 安装assimp失败

    使用Cmake和Visual Studio编译assimp成功(包括Debug和Release),并且安装Release版本也成功,但安装debug版本失败,安装输出信息如下: 通过提示找到脚本文件, ...

  9. WordPress函数小结

    1.body_class()函数 为了区分不同的页面,可以用WordPress的body_class()函数 可以在head.php中给body添加:<body <?php body_cl ...

  10. 仅1.0MB,开源压缩软件7-Zip

    首发微信公众号:SQL数据库运维 原文链接:https://mp.weixin.qq.com/s?__biz=MzI1NTQyNzg3MQ==&mid=2247485212&idx=1 ...