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 组件收到,回到顶部,重置状态
相关推荐
程序视点3 小时前
IObit Uninstaller Pro专业卸载,免激活版本,卸载清理注册表,彻底告别软件残留
前端·windows·后端
前端程序媛-Tian4 小时前
【dropdown组件填坑指南】—怎么实现下拉框的位置计算
前端·javascript·vue
嘉琪0014 小时前
实现视频实时马赛克
linux·前端·javascript
烛阴4 小时前
Smoothstep
前端·webgl
若梦plus5 小时前
Eslint中微内核&插件化思想的应用
前端·eslint
爱分享的程序员5 小时前
前端面试专栏-前沿技术:30.跨端开发技术(React Native、Flutter)
前端·javascript·面试
超级土豆粉5 小时前
Taro 位置相关 API 介绍
前端·javascript·react.js·taro
若梦plus5 小时前
Webpack中微内核&插件化思想的应用
前端·webpack
若梦plus5 小时前
微内核&插件化设计思想
前端
柯北(jvxiao)5 小时前
搞前端还有出路吗?如果有,在哪里?
前端·程序人生