轻松实现H5页面下拉刷新:滑动触发、高度提示与数据刷新全攻略
前段时间在做小程序到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~
轻松实现H5页面下拉刷新:滑动触发、高度提示与数据刷新全攻略的更多相关文章
- H5页面下拉加载更多(实用版)
		
近期在做一个H5网站,需要下拉加载更多产品列表的功能.百度搜索了好久,什么说法都有,什么插件都有. 醉了.基本上每一个能直接拿来用的. 最后发现: 1.dropload.js 插件 还可以,但是 ...
 - H5  页面下拉加载更多
		
1.html页面: <body onload="index_roll()"> ... </body> 2.js <script type=" ...
 - ios系统微信浏览器、safari浏览器中h5页面上拉下滑导致悬浮层脱离窗口的解决方法
		
一. 运行环境: iphone所有机型的qq浏览器,safari浏览器,微信内置浏览器(qq浏览器内核)等. 二. 异常现象: 1. 大幅度上下滑动h5页面,然后停止滑动,有时候会影响到页面滚动,如局 ...
 - 刷新各ifream当前页,下拉项改变触发事件js,给选中项加背景色js
		
<script type="text/javascript" language="javascript"> //刷新框架各页面 function r ...
 - 微信小程序 禁止ios页面下拉下滑滚动 出现空白的情况
		
项目需要做了一个图片拖动指定组件上删除,和排序的功能android测试正常, ios会出现拖动图片页面也跟着下滑的尴尬情况. 查文档下拉刷新配置默认是关闭的,后经查找文档发现在本页面page.json ...
 - 页面滚动动态加载数据,页面下拉自动加载内容 jquery
		
<!DOCTYPE=html> <html> <head> < script src="js/jquery.js" type=" ...
 - Jquery页面滚动动态加载数据,页面下拉自动加载内容
		
<!DOCTYPE=html> <html> <head> <script src="js/jquery.js" type="t ...
 - 微信h5页面下拉露出网页来源的解决办法
		
微信h5页面下拉露出网页来源的解决办法:将document的touchmove事件禁止掉 //禁止页面拖动 document.addEventListener('touchmove', functio ...
 - LayUI中select下拉框选中触发事件
		
代码: var form = layui.form, layer = layui.layer; // 监听 $(document).ready(function() { // select下拉框选中触 ...
 - H5 移动调试全攻略
		
H5 移动调试全攻略 随着移动设备的高速发展,H5 开发也成为了 F2E 不可或缺的能力.而移动开发的重中之重就是掌握调试技巧,定 Bug于无形. 一.概要 因为移动端操作系统分为 iOS 和 And ...
 
随机推荐
- 10个Bug环环相扣,你能解开几个?
			
简介:由阿里云云效主办的2021年第3届83行代码挑战赛已经收官.超2万人围观,近4000人参赛,85个团队组团来战.大赛采用游戏闯关玩儿法,融合元宇宙科幻和剧本杀元素,让一众开发者玩得不亦乐乎. ...
 - 什么是IPD项目管理模式?聊聊IPD下的产品研发流程
			
IPD(集成产品开发)涵盖了产品从创意提出到研发.生产.运营等,包含了产品开发到营销运营的整个过程.围绕产品(或项目)生命周期的过程的管理模式,是一套生产流程,更是时下国际先进的管理体系.IPD(集成 ...
 - 【web安全】修改和配置tomcat版本信息
			
场景 目前网络安全的越来越受重视,tomcat作为重要的web容器被广泛应用,如何隐藏信息保证.在开放网络世界中,不易被攻击. 操作思路 1.进入Tomcat文件中的lib文件夹,将catalina. ...
 - gin框架对接快递100 查询快递跟踪记录 Golang实现快递查询
			
参考ui效果: https://www.kuaidi100.com/?from=openv gin框架: 请求地址 http://localhost:8822/kd100/auto_com_num?n ...
 - GESP 202312 游记
			
day 0 把一本通上的指针扫了一遍,睡觉! day 1 9:00入场,在第二个考场. 冲进昌平二中,码了Hello,World!. 9:30发网址,开题 监考老师居然说阅读程序题可以打代码!···· ...
 - Splashtop :符合 HIPAA 标准的远程桌面软件
			
如果您正在寻找可帮助您保持 HIPAA 遵从性的远程桌面软件,那么 Splashtop 就是您的最佳选择. 如果您的公司属于美国医疗保健行业,则您知道您必须遵守有关敏感和私人患者信息的联邦 HIPAA ...
 - 前端 PM 分享:PM 需要做的事情
			
个人经验分享 PM PM( Project Manager ) PM( Product Manager ) 一.什么情况下需要前端担任 PM? 在我之前遇到的项目中,大多数项目的 PM 是由后端/产品 ...
 - mini-centos7 环境安装部署,各种踩坑。。。
			
最小Linux系统,安装Java环境 想想就生气,去面试个运维,面试官让我上机装个centos7,还是个最小安装包连界面都没有,只有命令行模式,我都哭了,然后让把一些环境装一下,然后再部署个sprin ...
 - 记一次DRF问题排障
			
1 最近在搞django,在写一个接口的时候用到了APIview,之后再调用接口的时候一直显示405,不允许使用post方法 视图
 - 逆向WeChat(三)
			
本篇在博客园地址https://www.cnblogs.com/bbqzsl/p/18198572 上篇回顾,对象是WEUIEngine.WeUIEngine使用了chrome::base框架,但只用 ...