轻松实现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~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/714755.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

手把手教你如何在Windows11下安装Docker容器

文章的主要要点&#xff1a; 为什么使用Docker&#xff1a;Docker可以简化部署过程&#xff0c;特别适合新手或在学习新技能&#xff08;如Redis、MySQL、消息队列、Nginx等&#xff09;时使用。 安装前的准备&#xff1a;在安装Docker之前&#xff0c;需要在Windows中开启一些…

python13 元组类型

元组用 () 声明&#xff0c;注意如果只有一个元素时要在元素后面加个 逗号, 否则不是类型就不是元组了。 声明方式2内置函数声明 data tuple(helloworld); 元组是不可变列表&#xff0c; 元组可以使用序列的所有功能。具体可以看我以前序列的文章 元组里的元素可以是多种数据类…

zynq qemu模拟器环境搭建

qemu是硬件模拟器&#xff0c;方便有些同学没得开发板想验证一些driver是否在指定板卡上可以测试&#xff0c;qemu就实现了该功能&#xff0c;选择qemu模拟器最好是选择cpu厂商指定qemu源码&#xff0c;这样测试结果更加逼真。本文章主要介绍如何搭建zynq平台qemu模拟器环境。 …

​单级高频谐振小放

目录 高频交流等效电路 质量指标 增益 通频带 选择性 高频交流等效电路 质量指标 增益 YL撇是怎么来的。 通频带 选择性

12 款 Android 照片恢复应用程序列表

丢失难忘的照片总是令人痛苦的。如果软件崩溃或意外删除&#xff0c;Android 设备上的照片也可能会丢失。这时照片恢复应用程序就派上用场了。查看我们为 Android 收集的顶级照片恢复应用程序。 但是&#xff0c;您不会想为自己选择任何照片恢复应用程序。因此&#xff0c;我们…

浅析Spring中Async注解底层异步线程池原理

一、前言 开发中我们经常会用到异步方法调用&#xff0c;具体到代码层面&#xff0c;异步方法调用的实现方式有很多种&#xff0c;比如最原始的通过实现Runnable接口或者继承Thread类创建异步线程&#xff0c;然后启动异步线程&#xff1b;再如&#xff0c;可以直接用java.uti…

Python爬虫JS逆向进阶课程

这门课程是Python爬虫JS逆向进阶课程&#xff0c;将教授学员如何使用Python爬虫技术和JS逆向技术获取网站数据。学习者将学习如何分析网站的JS代码&#xff0c;破解反爬虫机制&#xff0c;以及如何使用Selenium和PhantomJS等工具进行模拟登录和数据抓取。课程结合实例演练和项目…

【鸿蒙 HarmonyOS】Swiper组件

一、背景 项目中通常会遇到图片轮播&#xff0c;内容轮播的场景&#xff1b;如&#xff1a;在一些应用首页显示推荐的内容时&#xff0c;需要用到轮播显示的能力。 二、源码地址 ✍Gitee开源项目地址&#x1f449;&#xff1a;https://gitee.com/cheinlu/harmony-os-next-swi…

【JKI SMO】框架讲解(二)

JKI State Machine 讲解 将JKI State Machine 模板拖曳到程序框图中&#xff0c; 如下图&#xff0c; 此模板会默认放置一个OK按钮在前面板中&#xff0c;用于提示用户如何增加一个简单的用户事件去使用此框架。 “Event Structure”&#xff0c;Idle&#xff1a;此分支可以设…

3D ToF赋能小米CyberDog 2提升视觉灵敏度

随着科技的进步,智能机器人越来越多地融入我们的日常生活。其中,CyberDog 2作为一款前沿的四足机器人,凭借其出色的视觉灵敏度和多功能技术配备,受到了广泛的关注。本文将重点探讨CyberDog 2的视觉系统,尤其是其四种不同类型的摄像头如何共同提升其视觉灵敏度,以及激光传…

c++_0基础_讲解7 练习

这一讲我为大家准备了几道题目&#xff0c;大家试着独自做一下&#xff08;可能来自不同网站&#xff09; 整数大小比较 - 洛谷 题目描述 输入两个整数&#xff0c;比较它们的大小。若 x>yx>y &#xff0c;输出 > &#xff1b;若 xyxy &#xff0c;输出 &#xff…

在ubuntu中恢复误删除的文件

1、安装 TestDisk 在 Ubuntu 上&#xff0c;可以使用以下命令安装 TestDisk&#xff1a; sudo apt-get install testdisk2、查询你删除的文件所在那个分区 #查询分区 df -h #我这里是/dev/sda2 #也可以使用下面命令查看具体哪个分区 lsblk3、查询该分区是什么系统类型 sudo …

【CICID】GitHub-Actions语法

[TOC] 【CICID】GitHub-Actions语法 1 场景 ​ 当我们开发过程中&#xff0c;经常需要提交代码&#xff0c;打包&#xff0c;部署新代码到对应的环境&#xff0c;整个过程都是人工手动操作&#xff0c;占据开发人员大量时间&#xff0c;并且很繁琐容易出错。所以需要借助一些…

redis 缓存jwt令牌设置更新时间 BUG修复

大家好&#xff0c;今天我又又又来了&#xff0c;hhhhh。 上文中 我们永redis缓存了token 但是我们发现了 一个bug &#xff0c;redis中缓存的token 是单用户才能实现的。 就是 我 redis中存储的键 名 为token 值 是jwt令牌 &#xff0c;但是如果 用户a 登录 之后 创建一个…

LeetCode43.字符串相乘【大整数相乘】

LeetCode刷题记录 文章目录 &#x1f4dc;题目描述&#x1f4a1;解题思路 &#x1f4dc;题目描述 给定两个以字符串形式表示的非负整数 num1 和 num2&#xff0c;返回 num1 和 num2 的乘积&#xff0c;它们的乘积也表示为字符串形式。 注意&#xff1a;不能使用任何内置的 Big…

C++ 算法教程

归并排序 #include<iostream> using namespace std; template <class T> void Merge(T data[],int start,int mid,int end) {int len1 mid - start 1, len2 end - mid;int i, j, k;T* left new int[len1];T* right new int[len2];for (i 0; i < len1; i)…

数据结构--力扣104,110 二叉树相关(C

1.力扣104。二叉树的最大深度-. - 力扣&#xff08;LeetCode&#xff09; 2.力扣110。平衡二叉树->. - 力扣&#xff08;LeetCode&#xff09; 1. 叶子结点 指&#xff1a;没有子节点的节点 思路&#xff1a; 求其 左子树和右子树的最大深度&#xff0c;返回其中最大值即可…

《C语言》文件操作

文章目录 一、认识文件1、文件的概念2、程序文件3、数据文件4、文件名 三、二进制文件和文本文件四、文件的打开和关闭1、流2、标准流3、文件指针4、文件的关闭和打开 四、文件的顺序读写文件的随机读写1、fseek2、ftell3、rewind4.int origin 一、认识文件 主要讨论数据文件 1…

C++ 矩阵乘法

描述 如果A是个x行y列的矩阵&#xff0c;B是个y行z列的矩阵&#xff0c;把A和B相乘&#xff0c;其结果将是另一个x行z列的矩阵C。这个矩阵的每个元素是由下面的公式决定的 矩阵的大小不超过100*100 输入描述&#xff1a; 第一行包含一个正整数x&#xff0c;代表第一个矩阵的…

Go如何在本地引用以及发布并引用自定义工具包

如何引用本地自定义工具包 我们首先要准备两个项目&#xff0c;分别为需要引入的工具包和当前项目。 myutils、myproject1. myutils为我们的项目1-工具包 package mypakgeimport "strings"func IsContains(s string) bool {if strings.Contains(s, "a")…