查看: 110|回复: 1

Vue3集成NProgress进度条的完整实践:安装、封装、Axios与路由守卫

[复制链接]
发表于 3 小时前 | 显示全部楼层 |阅读模式
在Vue3项目中,一个运行中的进度条能显著提升用户体验,尤其适合长耗时请求或页面切换场景。NProgress作为轻量级进度条库,搭配TypeScript和Vite环境,可优雅地融入现有项目。下面分享一套经过验证的集成方案,涵盖基础安装、可配置Hook封装、Axios拦截器和Vue Router守卫集成,以及全局样式自定义。

一、环境准备
首先安装核心依赖和类型定义:
  1. pnpm i nprogress lodash-es
  2. pnpm i @types/nprogress @types/lodash-es -D
复制代码
nprogress提供进度控制API,lodash-es用于对象深度合并。类型声明仅在开发时使用。

通过环境变量控制进度条开关,在.env文件中加入:
  1. VITE_ROUTER_NPROGRESS = true
  2. VITE_REQUEST_NPROGRESS = true
复制代码
设置为'false'即可关闭对应场景的进度条,无需修改代码。

二、核心封装:useProgress Hook
创建一个可复用的组合式函数,统一配置进度条行为。
  1. // src/hooks/useProgress.ts
  2. import { merge } from 'lodash-es'
  3. import NProgress from 'nprogress'
  4. import type { NProgressOptions } from 'nprogress'
  5. interface ProgressConfig extends NProgressOptions {
  6.   show: boolean
  7. }
  8. const DEFAULT_CONFIG: Partial<ProgressConfig> = {
  9.   easing: 'ease',
  10.   parent: 'body',
  11.   show: true,
  12.   showSpinner: false,
  13.   trickle: true,
  14.   minimum: 0.08,
  15.   speed: 200,
  16. }
  17. export function useProgress(config: Partial<ProgressConfig> = {}) {
  18.   const mergeConfig = merge({}, DEFAULT_CONFIG, config)
  19.   NProgress.configure(mergeConfig)
  20.   function start() {
  21.     if (!mergeConfig.show) return
  22.     NProgress.start()
  23.   }
  24.   function done() {
  25.     if (!mergeConfig.show || !NProgress.isStarted()) return
  26.     NProgress.done()
  27.   }
  28.   return { start, done }
  29. }
复制代码
该Hook接受自定义配置,与默认配置深度合并后调用NProgress.configure。start和done方法根据show属性决定是否实际执行,避免因环境变量关闭带来的无谓调用。

三、实际应用场景
1. Axios请求拦截器集成
创建通用请求模块,在请求发送前启动进度条,请求完成后结束。
  1. // src/utils/request.ts
  2. import axios from 'axios'
  3. import { useProgress } from '@/hooks/useProgress'
  4. const NProgress = useProgress({ show: import.meta.env.VITE_REQUEST_NPROGRESS !== 'false' })
  5. const instance = axios.create({
  6.   baseURL: import.meta.env.VITE_API_BASE_URL,
  7.   timeout: 15000,
  8. })
  9. instance.interceptors.request.use(
  10.   (config) => {
  11.     NProgress.start()
  12.     return config
  13.   },
  14.   (error) => {
  15.     NProgress.done()
  16.     return Promise.reject(error)
  17.   }
  18. )
  19. instance.interceptors.response.use(
  20.   (response) => {
  21.     NProgress.done()
  22.     return response
  23.   },
  24.   (error) => {
  25.     NProgress.done()
  26.     return Promise.reject(error)
  27.   }
  28. )
  29. export const request = instance
复制代码
注意:在请求或响应错误时也要调用done,防止进度条卡住。

2. Vue Router路由守卫集成
在路由切换时自动显示进度条,通过环境变量控制。
  1. // src/router/index.ts
  2. import { createRouter, createWebHistory } from 'vue-router'
  3. import { useProgress } from '@/hooks/useProgress'
  4. const router = createRouter({
  5.   history: createWebHistory(),
  6.   routes: [],
  7. })
  8. const NProgress = useProgress({ show: import.meta.env.VITE_ROUTER_NPROGRESS !== 'false' })
  9. router.beforeEach((to, from, next) => {
  10.   NProgress.start()
  11.   next()
  12. })
  13. router.afterEach(() => {
  14.   NProgress.done()
  15. })
  16. export default router
复制代码
若使用了异步路由,确保在路由解析完成后执行done,避免过早结束。

3. 组合式调用示例
在Vue组件的任何异步操作中也可手动调用:
  1. <script setup lang="ts">
  2. import { useProgress } from '@/hooks/useProgress'
  3. const NProgress = useProgress({ show: import.meta.env.VITE_REQUEST_NPROGRESS !== 'false' })
  4. async function loadData() {
  5.   NProgress.start()
  6.   try {
  7.     await fetch('/api/data')
  8.   } finally {
  9.     NProgress.done()
  10.   }
  11. }
  12. </script>
复制代码
务必使用try...finally确保进度条能正确结束。

四、全局样式自定义
NProgress默认提供朴素样式,通常需与项目主题匹配。推荐在全局样式入口文件中覆盖。

创建src/styles/nprogress.scss,定义渐变色进度条:
  1. // src/styles/nprogress.scss
  2. #nprogress .bar {
  3.   background: var(--el-color-primary);
  4.   height: 3px;
  5.   background: linear-gradient(90deg, var(--el-color-primary-light-3) 0%, var(--el-color-primary) 100%);
  6. }
  7. #nprogress .peg {
  8.   box-shadow: 0 0 10px var(--el-color-primary);
  9. }
  10. #nprogress .spinner-icon {
  11.   border-top-color: var(--el-color-primary);
  12.   border-left-color: var(--el-color-primary);
  13. }
复制代码
然后新建src/styles/index.scss,统一导入:
  1. @use 'nprogress.scss';
  2. @use 'variables.scss';
  3. @use 'transition.scss';
  4. @use 'element-plus/el-table.scss';
  5. @use 'element-plus/el-dialog.scss';
  6. @use 'element-plus/el-dropdown.scss';
  7. body {
  8.   font-family: var(--el-font-family);
  9.   background-color: var(--el-bg-color-page);
  10. }
复制代码
最后在main.ts引入:
  1. import { createApp } from 'vue'
  2. import App from './App.vue'
  3. import './styles/index.scss'
  4. const app = createApp(App)
  5. app.mount('#app')
复制代码
注意:如果有其他样式文件,顺序需处理好。若不需要自定义,也可以直接引入nprogress自带的CSS:
  1. @use 'nprogress/nprogress.css';
复制代码

五、NProgress配置项详解
配置项支持以下参数(配置通过NProgress.configure传入):
  1. {
  2.   easing: 'ease',       // CSS3缓动函数
  3.   speed: 200,           // 动画速度(ms)
  4.   trickle: true,        // 是否自动递增
  5.   trickleSpeed: 200,    // 自动递增速度
  6.   minimum: 0.08,        // 起始百分比(0-1)
  7.   showSpinner: false,   // 是否显示环形加载动画
  8.   parent: 'body',       // 父容器CSS选择器
  9.   positionUsing: '',    // 定位方式(可选'absolute','fixed'等)
  10. }
复制代码
缓动函数推荐使用标准值或自定义贝塞尔曲线,例如:
  1. const EASING_FUNCTIONS = {
  2.   linear: 'linear',
  3.   ease: 'ease',
  4.   smooth: 'cubic-bezier(0.4, 0, 0.2, 1)',
  5.   gentle: 'cubic-bezier(0.25, 0.1, 0.25, 1)',
  6.   swift: 'cubic-bezier(0.4, 0, 0.6, 1)',
  7. }
复制代码
可根据项目视觉风格灵活调整。

以上方案已在多个Vue3+TypeScript项目中使用,通过环境变量和配置Hook,能轻松控制进度条的显示与行为,并与Axios、Vue Router深度整合。希望这套封装能帮你快速落地NProgress,提升应用的用户反馈体验。
回复

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: Vue3集成NProgress进度条的完整实践:安装、封装、Axios与路由守卫

感谢楼主的详细分享!正好最近在重构一个Vue3项目,进度条这块一直想整合但没找到清晰的方案。你这种通过环境变量控制开关的思路很实用,特别是用lodash-es做深度合并来统一配置,既灵活又干净。请教一下,在路由守卫里如果用了异步路由(比如动态加载组件),有没有遇到过进度条提前结束的情况?我看你提到了“确保在路由解析完成后执行done”,具体是怎么判断解析完成的?另外,组件里手动调用时,如果并发多个请求,start/done的配对会不会有冲突?希望再展开说说,谢谢!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-6-12 20:07 , Processed in 0.026710 second(s), 18 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部