轻松实现H5页面下拉刷新:滑动触发、高度提示与数据刷新全攻略

h5 · 浏览次数 : 0

小编点评

本文介绍了如何在H5页面实现下拉刷新功能。由于原生小程序中的下拉刷新功能与H5页面的其他功能存在兼容性问题,作者决定自行实现该功能。文章首先概述了下拉刷新功能的流程,然后详细阐述了具体的实现步骤,包括CSS样式、JavaScript事件监听以及与页面交互的细节。最后,提供了一个完整的GitHub代码示例。 1. **功能概述**: 本文首先介绍了下拉刷新功能的背景和需求,指出在迁移过程中遇到的兼容性问题,并提出自行实现该功能的方案。 2. **流程分析**: 接着,文章分析了实现下拉刷新功能所需的主要步骤,包括: - 监听手指触摸事件 - 根据触摸事件判断滑动方向和操作轨迹 - 判断是否首屏以及是否可以进行下拉操作 - 控制数据加载和展示 3. **实现步骤**: 文章详细说明了每个实现步骤的具体实现方法,包括: - CSS样式设计,如下拉内容的展示和动画效果 - JavaScript事件监听,用于处理触摸开始、触摸移动和触摸结束等事件 - 数据请求和加载状态的同步处理 4. **完整代码示例**: 最后,文章提供了一个GitHub代码示例,包括HTML、CSS和JavaScript文件,供读者参考和下载。 总的来说,文章通过详细的步骤和代码示例,展示了如何在H5页面实现下拉刷新功能,为遇到类似问题的开发者提供了实用的解决方案。

正文

前段时间在做小程序到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页面下拉刷新:滑动触发、高度提示与数据刷新全攻略相似的内容:

轻松实现H5页面下拉刷新:滑动触发、高度提示与数据刷新全攻略

前段时间在做小程序到H5的迁移,其中小程序中下拉刷新的功能引起了产品的注意。他说到,哎,我们迁移后的H5页面怎么没有下拉刷新,于是乎,我就急忙将这部分的内容给填上。 本来是计划使用成熟的组件库来实现,尝试之后发现这些组件和我们H5页面的其他逻辑有冲突(H5还有吸顶、锚点、滑动高亮、横向滚动),小小H

SpringBoot+mail 轻松实现各类邮件自动推送

一、简介 在实际的项目开发过程中,经常需要用到邮件通知功能。例如,通过邮箱注册,邮箱找回密码,邮箱推送报表等等,实际的应用场景非常的多。 早期的时候,为了能实现邮件的自动发送功能,通常会使用 JavaMail 相关的 api 来完成。后来 Spring 推出的 JavaMailSender 工具,进

云图说丨初识华为云OrgID:轻松实现统一帐号、统一授权

组织成员帐号 OrgID是面向企业提供组织管理、企业成员帐号管理以及SaaS应用授权管理能力的云服务。

[转帖]基于腾讯云微服务引擎(TSE) ,轻松实现云上全链路灰度发布

https://my.oschina.net/u/4587289/blog/8570699 1. 概述 软件开发过程中,应用发布非常频繁,通常情况下,开发或运维人员会将系统里所有服务同时上线,使得所有用户都使用上新版本。这样的操作时常会导致发布失败,或因发布前修改代码,线上出现 Bug。 假设一个在

百度飞桨(PaddlePaddle) - PP-OCRv3 文字检测识别系统 基于 Paddle Serving快速使用(服务化部署 - CentOS 7)

Paddle Serving 是飞桨服务化部署框架,能够帮助开发者轻松实现从移动端、服务器端调用深度学习模型的远程预测服务。 Paddle Serving围绕常见的工业级深度学习模型部署场景进行设计,具备完整的在线服务能力,支持的功能包括多模型管理、模型热加载、基于Baidu-RPC的高并发低延迟响应能力、在线模型A/B实验等,并提供简单易用的Client API。Paddle Serving可以

WPF使用TextBlock实现查找结果高亮显示

在应用开发过程中,经常遇到这样的需求:通过关键字查找数据,把带有关键字的数据显示出来,同时在结果中高亮显示关键字。在web开发中,只需在关键字上加一层标签,然后设置标签样式就可以轻松实现。 在WPF中显示文本内容通常采用`TextBlock`控件,也可以采用类似的方式,通过内联流内容元素`Run`达

从零开始学Spring Boot系列-集成Spring Security实现用户认证与授权

在Web应用程序中,安全性是一个至关重要的方面。Spring Security是Spring框架的一个子项目,用于提供安全访问控制的功能。通过集成Spring Security,我们可以轻松实现用户认证、授权、加密、会话管理等安全功能。本篇文章将指导大家从零开始,在Spring Boot项目中集成S

kettle从入门到精通 第六十九课 ETL之kettle kettle cdc mysql,轻松实现实时增量同步

1、之前kettle cdc mysql的时候使用的方案是canal+kafka+kettle,今天我们一起学习下使用kettle的插件Debezium直接cdc mysql。 注:CDC (Change Data Capture) 是一种技术,用于捕获和同步数据库中的更改。 1)Debezium步

LangChain转换链:让数据处理更精准

在开发AI Agent(智能体)时,我们经常需要对输入数据进行预处理,这样可以更好地利用LLM。LangChain提供了一个强大的工具——转换链(TransformChain),它可以帮我们轻松实现这一任务。

基于 ActionFilters 的限流库DotNetRateLimiter使用

前言 在构建API项目时,有时出于安全考虑,防止访问用户恶意攻击,希望限制此用户ip地址的请求次数,减轻拒绝服务攻击可能性,也称作限流。接下来,我们就来学习开源库DotNetRateLimiter 如何轻松实现限流。 项目使用配置 安装Nuget包 在新建立的WebAPI项目中,通过Nuget包管理