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

React中类似YouTube/GitHub顶部水平加载进度条实现方法咨询

嘿,这个问题抓得很准!那种像YouTube、GitHub一样的顶部加载进度条,核心可不是花架子——它是真的和实际的网络请求、页面加载进度挂钩的,网络慢的时候自然会停在对应阶段。我给你分享两种最常用的实现思路,从快速上手到自定义都有:

一、路由切换场景:配合React Router实现

大部分时候这种进度条是在页面路由跳转时触发的(比如切换页面加载数据),这里用轻量库nprogress配合React Router来快速实现,省心又好用:

步骤1:安装依赖

npm install nprogress react-router-dom

步骤2:封装进度条组件

新建一个ProgressBar.jsx,用来监听路由变化并控制进度条:

import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
import NProgress from 'nprogress';
import 'nprogress/nprogress.css'; // 别忘了引入默认样式

const ProgressBar = () => {
  const location = useLocation();

  useEffect(() => {
    // 路由开始切换时启动进度条
    NProgress.start();
    
    // 如果你想让进度条和页面数据加载联动,这里不要用固定延迟,而是在页面组件里手动控制进度
    const finishTimer = setTimeout(() => {
      NProgress.done();
    }, 300);

    // 路由取消或组件卸载时,确保进度条结束
    return () => {
      clearTimeout(finishTimer);
      NProgress.done();
    };
  }, [location]);

  return null; // 这个组件只做逻辑处理,不需要渲染DOM
};

export default ProgressBar;

步骤3:全局引入组件

在你的根组件App.jsx里,把进度条组件放在路由外层:

import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import ProgressBar from './ProgressBar';
import Home from './pages/Home';
import About from './pages/About';

function App() {
  return (
    <Router>
      <ProgressBar />
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
      </Routes>
    </Router>
  );
}

进阶:和实际数据加载联动

如果不想用固定延迟,而是让进度条跟着数据请求走,比如在Home页面里:

import { useEffect, useState } from 'react';
import NProgress from 'nprogress';

const Home = () => {
  const [data, setData] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        NProgress.set(0.3); // 手动设置进度:请求开始
        const res = await fetch('/api/home-data');
        NProgress.set(0.7); // 请求已响应,正在解析数据
        const result = await res.json();
        setData(result);
        NProgress.done(); // 数据加载完成,结束进度条
      } catch (err) {
        NProgress.done(); // 出错也要结束进度条
        console.error('数据加载失败:', err);
      }
    };

    fetchData();
  }, []);

  return (
    <div className="home-page">
      {data ? <div>{data.content}</div> : <p>加载中...</p>}
    </div>
  );
};
二、全局API请求场景:拦截所有网络请求

如果要让进度条监听所有的API请求(不管是不是路由切换触发的),可以用axios的拦截器来实现全局控制:

步骤1:安装依赖

npm install axios nprogress

步骤2:封装axios实例

新建api.js,在里面配置请求/响应拦截器:

import axios from 'axios';
import NProgress from 'nprogress';

// 创建axios实例
const api = axios.create({
  baseURL: '/api', // 你的API基础路径
});

// 请求拦截器:发起请求时启动进度条
api.interceptors.request.use(
  (config) => {
    NProgress.start();
    return config;
  },
  (error) => {
    NProgress.done(); // 请求失败也要结束进度条
    return Promise.reject(error);
  }
);

// 响应拦截器:请求完成(成功/失败)时结束进度条
api.interceptors.response.use(
  (response) => {
    NProgress.done();
    return response;
  },
  (error) => {
    NProgress.done();
    return Promise.reject(error);
  }
);

export default api;

之后所有的API请求都用这个api实例发起,进度条就会自动跟着所有请求的状态走——网络慢的时候,请求没完成,进度条就会停在当前状态,直到请求结束。

三、完全自定义实现(不用第三方库)

如果你不想依赖第三方库,也可以自己手写一个进度条组件,灵活性更高:

1. 自定义进度条组件

新建CustomProgressBar.jsx:

import { useState, useEffect } from 'react';
import './CustomProgressBar.css';

const CustomProgressBar = ({ isLoading, progress }) => {
  const [currentProgress, setCurrentProgress] = useState(0);

  useEffect(() => {
    if (isLoading) {
      // 模拟进度增长,也可以直接使用传入的progress值
      const progressTimer = setInterval(() => {
        setCurrentProgress((prev) => {
          if (prev >= progress) return prev;
          return prev + 5;
        });
      }, 100);

      return () => clearInterval(progressTimer);
    } else {
      // 加载完成后,让进度条走到100%再隐藏
      setCurrentProgress(100);
      const hideTimer = setTimeout(() => {
        setCurrentProgress(0);
      }, 300);
      return () => clearTimeout(hideTimer);
    }
  }, [isLoading, progress]);

  return (
    <div className="progress-bar-container">
      <div
        className="progress-bar"
        style={{ width: `${currentProgress}%` }}
      />
    </div>
  );
};

export default CustomProgressBar;

2. 编写样式文件CustomProgressBar.css

.progress-bar-container {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 3px;
  background-color: #f5f5f5;
  z-index: 9999; /* 确保在最顶层 */
}

.progress-bar {
  height: 100%;
  background-color: #2196f3;
  transition: width 0.2s ease-in-out;
}

3. 使用自定义进度条

在需要的地方引入并控制状态,比如路由监听组件:

import { useState, useEffect } from 'react';
import { useLocation } from 'react-router-dom';
import CustomProgressBar from './CustomProgressBar';

const ProgressWrapper = () => {
  const [isLoading, setIsLoading] = useState(false);
  const [progress, setProgress] = useState(0);
  const location = useLocation();

  useEffect(() => {
    setIsLoading(true);
    setProgress(0);

    // 模拟实际的数据请求流程
    const fetchPageData = async () => {
      try {
        setProgress(30);
        await new Promise(resolve => setTimeout(resolve, 1200)); // 模拟网络请求延迟
        setProgress(70);
        await new Promise(resolve => setTimeout(resolve, 800));
        setProgress(100);
        setIsLoading(false);
      } catch (err) {
        setIsLoading(false);
        console.error('加载失败:', err);
      }
    };

    fetchPageData();
  }, [location]);

  return <CustomProgressBar isLoading={isLoading} progress={progress} />;
};

核心总结一下:这种进度条的关键是让进度状态和实际的加载/请求生命周期绑定,而不是单纯播放循环动画。网络慢的时候,只要请求没完成,进度就会停在对应阶段,直到请求结束才会完成。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 09:25:12