You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在React中正确实现加载进度条的动画效果?

React加载进度条3秒内从0到100%的修复方案

问题说明

在React中构建加载进度条时,期望进度条在3秒内从0宽度平滑增长至100%,但当前代码无法实现该预期效果。

原代码问题分析

  1. CSS过渡与JS定时器冲突:原CSS中给进度条添加了transition: width 3.05s linear,这会和JS定时器驱动的宽度更新产生冲突,导致动画效果异常。
  2. 进度计算精度问题:原代码通过定时器间隔10ms累加增量的方式,会因为时间精度误差导致进度无法准确在3秒时到达100%。
  3. 布局定位缺失:进度条容器.canvas未设置position: relative,导致绝对定位的进度条布局脱离预期范围。

修复方案

以下提供两种可行的实现方式,按需选择:


方案一:使用requestAnimationFrame精准控制(灵活可控)

通过requestAnimationFrame替代定时器,基于时间差计算进度,保证动画的精准性和流畅度。

修改后的JS代码:

const { useState, useEffect } = React;

const Loading = () => {
  const [isLoading, setIsLoading] = useState(true);
  const [progress, setProgress] = useState(0);

  useEffect(() => {
    const duration = 3000;
    const startTime = Date.now();
    
    const updateProgress = () => {
      // 计算已流逝时间占总时长的比例,转换为进度百分比
      const elapsed = Date.now() - startTime;
      const newProgress = Math.min((elapsed / duration) * 100, 100);
      setProgress(newProgress);
      
      // 未完成则继续更新,完成后终止加载状态
      if (newProgress < 100) {
        requestAnimationFrame(updateProgress);
      } else {
        setIsLoading(false);
      }
    };

    const animationFrameId = requestAnimationFrame(updateProgress);
    
    // 组件卸载时取消动画帧
    return () => cancelAnimationFrame(animationFrameId);
  }, []);

  return (
    <div className="canvas">
      {isLoading && (
        <div
          className="loading_bar"
          style={{ width: `${progress}%` }}
        ></div>
      )}
    </div>
  );
};

// 渲染组件
ReactDOM.createRoot(
  document.getElementById("root")
).render(
  <Loading />
);

修改后的CSS代码:

/* 给容器添加相对定位,确保进度条在容器内定位 */
.canvas {
  position: relative;
  width: 100%;
  height: 5px;
}

.loading_bar {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  background-color: #c4483f;
  /* 移除transition,由JS完全控制宽度变化 */
}

HTML代码:

<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.js"></script>

方案二:纯CSS动画实现(简洁高效)

如果不需要动态调整进度,直接用CSS动画更简洁,无需JS定时器控制。

修改后的JS代码:

const { useState, useEffect } = React;

const Loading = () => {
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    // 3秒后结束加载状态
    const timer = setTimeout(() => {
      setIsLoading(false);
    }, 3000);
    
    return () => clearTimeout(timer);
  }, []);

  return (
    <div className="canvas">
      {isLoading && <div className="loading_bar"></div>}
    </div>
  );
};

// 渲染组件
ReactDOM.createRoot(
  document.getElementById("root")
).render(
  <Loading />
);

修改后的CSS代码:

.canvas {
  position: relative;
  width: 100%;
  height: 5px;
}

.loading_bar {
  position: absolute;
  top: 0;
  left: 0;
  width: 0;
  height: 100%;
  background-color: #c4483f;
  /* 使用CSS动画实现3秒内宽度从0到100% */
  animation: loadProgress 3s linear forwards;
}

@keyframes loadProgress {
  to {
    width: 100%;
  }
}

HTML代码同上。

方案对比

  • 方案一适合需要中途调整进度、暂停/恢复动画等复杂场景;
  • 方案二代码更简洁,性能更优,适合固定时长的简单加载进度需求。

内容的提问来源于stack exchange,提问作者mrconcerned

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 21:57:11