90%的人都在用的下拉刷新,我把它拆了!

你有没有在手机上刷微博、刷朋友圈、刷小红书的时候,手指从上往下拉一下,页面就自动刷新了?这就是我们常说的------下拉刷新功能。

今天,我们就来揭开它的神秘面纱,看看它是怎么用代码实现的。

一、下拉刷新到底是什么?

想象一下:你正在看一个笔记列表,突然想看看有没有新内容。于是你用手指从屏幕顶部往下拉,这时页面会:

  1. 向下移动(像被你拽下来一样)
  2. 显示"下拉刷新..." → "释放刷新..." → "加载中..."
  3. 松手后,重新加载新数据
  4. 加载完自动弹回去

这个过程,就是"下拉刷新"。

我们要做的,就是用代码模拟这个交互行为


二、核心思路:四个关键步骤

整个下拉刷新组件的实现,可以分成 4 个步骤

  1. 👉 监听用户的手指动作(触摸开始、移动、结束)
  2. 📊 管理状态(比如当前拉了多少距离)
  3. 🎨 实现动画效果(下拉和回弹)
  4. 🔗 和父组件通信(告诉它"该刷新数据啦!")

下面我们一个一个来看。


三、第一步:监听用户的手指操作

我们要知道用户什么时候开始拉、拉了多少、什么时候松手。这就要靠触摸事件

1. onTouchStart:记录起始位置

js 复制代码
const onTouchStart = (e) => {
  const start_y = e.touches[0].clientY
  setStartY(start_y)
}

👉 解释:当用户手指刚碰到屏幕时,记录下触摸的Y坐标(比如是屏幕第500像素的位置),保存起来。


2. onTouchMove:计算下拉距离

js 复制代码
const onTouchMove = (e) => {
  const move_y = e.touches[0].clientY
  if (move_y < startY) return  // 防止向上滑动也触发

  setDistance(move_y - startY)  // 当前拉了多少距离
  setTranslateY(distance ** 0.8) // 控制页面下移多少(更自然)

  if (distance >= 100) {
    setCurrent('释放刷新...')
  }
}

👉 解释:

  • 用户一边拉,我们就一边计算他拉了多少(move_y - startY)。
  • 我们不让页面跟着拉多少就下移多少,而是用了个"指数函数 "(distance ** 0.8),这样越拉越慢,手感更顺滑。
  • 当拉到 100px 以上,就提示用户:"可以松手啦!"

3. onTouchEnd:松手后判断是否刷新

js 复制代码
const onTouchEnd = () => {
  if (distance >= 100) {
    setCurrent('加载中...')
    // 开始回弹动画
    timer = setInterval(() => {
      setTranslateY(prev => prev - 5)
    }, 20)
    onLoad()  // 调用父组件的加载函数
  }
}

👉 解释:

  • 用户松手时,如果拉的距离够长(≥100px),就认为"我要刷新"。
  • 显示"加载中..."
  • 启动一个定时器,每20毫秒让页面往上移5px,实现"慢慢弹回去"的动画。
  • 同时调用 onLoad(),告诉父组件:"快去加载新数据吧!"

四、第二步:用状态管理记住关键数据

React 中用 useState 来保存各种状态:

js 复制代码
const [startY, setStartY] = useState(0)     // 起始Y坐标
const [distance, setDistance] = useState(0) // 当前拉了多少
const [translateY, setTranslateY] = useState(0) // 页面下移多少
const [current, setCurrent] = useState('下拉刷新...') // 状态文字

这些变量就像"记忆",让程序知道现在处于什么阶段。

✅ 小知识:useState 是 React 的"状态钩子",可以让函数组件记住数据。


五、第三步:让页面动起来------动画效果

我们通过 CSS 的 transform: translateY() 来控制页面下移:

jsx 复制代码
<div style={{ transform: `translateY(${translateY}px)` }}>
  {children}
</div>
  • translateY 越大,页面就越往下"飘"。
  • 松手后,我们用 setInterval 每次减5px,直到回到顶部,实现平滑回弹

还有一个细节:当页面快回到顶部时(比如 ≤40px),就清除定时器,防止无限执行:

js 复制代码
useEffect(() => {
  if (translateY <= 40) {
    clearInterval(timer)
  }
}, [translateY])

✅ 这叫"副作用监听",useEffect 会自动检测 translateY 变化。


六、第四步:和外面的世界沟通------组件通信

我们的下拉组件是"通用"的,它不知道该加载什么数据。所以需要父组件告诉它

jsx 复制代码
<Pull onLoad={onLoad} finished={finished} setFinished={setFinished}>
  <section>你的内容</section>
</Pull>
  • onLoad:松手后要执行的函数(比如重新请求接口)
  • finished:加载是否完成
  • setFinished:用来重置状态

当数据加载完成后,父组件设置 setFinished(true),下拉组件收到后就会自动回到顶部:

js 复制代码
useEffect(() => {
  if (finished) {
    setTranslateY(0)
    setFinished(false) // 重置,准备下次刷新
  }
}, [finished])

✅ 这就是"父子组件通信",通过 props 传递函数和状态。


七、完整流程图解

scss 复制代码
用户下拉
   ↓
onTouchStart 记录起点
   ↓
onTouchMove 计算距离,更新UI
   ↓
松手时 onTouchEnd 判断是否够长
   ↓
够长?→ 显示"加载中" + 启动回弹动画 + 调用 onLoad()
   ↓
onLoad() 请求新数据
   ↓
数据加载完,父组件 setFinished(true)
   ↓
Pull 组件收到,回到顶部,重置状态
相关推荐
程序员码歌28 分钟前
短思考第261天,浪费时间的十个低效行为,看看你中了几个?
前端·ai编程
Swift社区1 小时前
React Navigation 生命周期完整心智模型
前端·react.js·前端框架
若梦plus1 小时前
从微信公众号&小程序的SDK剖析JSBridge
前端
用泥种荷花2 小时前
Python环境安装
前端
Light602 小时前
性能提升 60%:前端性能优化终极指南
前端·性能优化·图片压缩·渲染优化·按需拆包·边缘缓存·ai 自动化
Jimmy2 小时前
年终总结 - 2025 故事集
前端·后端·程序员
烛阴2 小时前
C# 正则表达式(2):Regex 基础语法与常用 API 全解析
前端·正则表达式·c#
roman_日积跬步-终至千里2 小时前
【人工智能导论】02-搜索-高级搜索策略探索篇:从约束满足到博弈搜索
java·前端·人工智能
GIS之路2 小时前
GIS 数据转换:使用 GDAL 将 TXT 转换为 Shp 数据
前端
多看书少吃饭2 小时前
从Vue到Nuxt.js
前端·javascript·vue.js