Vue3 集成 NProgress 进度条:从入门到精通
2026年4月23日 11:31
在前端应用开发中,用户体验至关重要。当页面加载或进行数据请求时,一个优雅的进度条不仅能告知用户系统正在工作,还能有效缓解用户的等待焦虑。NProgress 作为一款轻量级的进度条库,凭借其简洁的设计和良好的兼容性,被广泛应用于各类 Web 项目中。本文将详细介绍如何在 Vue3 项目中优雅地集成和使用 NProgress。
一、环境准备
1.1 安装依赖
# 安装 NProgress 核心库和 lodash-es 工具库
pnpm i nprogress lodash-es
# 安装 TypeScript 类型定义(开发依赖)
pnpm i @types/nprogress @types/lodash-es -D
1.2 依赖说明
- nprogress:进度条核心库,提供简单的进度控制 API
- lodash-es:高效的 JavaScript 工具库,用于对象合并等操作
- @types/nprogress:NProgress 的 TypeScript 类型定义文件
- @types/lodash-es:lodash-es 的 TypeScript 类型定义文件
1.3 环境变量配置
在 .env 文件中配置进度条的开关:
# 路由进度条,默认开启(设置为 'false' 可关闭)
VITE_ROUTER_NPROGRESS = true
# 请求进度条,默认开启(设置为 'false' 可关闭)
VITE_REQUEST_NPROGRESS = true
二、核心实现
2.1 基础封装
// src/hooks/useProgress.ts
import { merge } from 'lodash-es'
import NProgress from 'nprogress'
import type { NProgressOptions } from 'nprogress'
interface ProgressConfig extends NProgressOptions {
/** 是否显示进度条 */
show: boolean
}
const DEFAULT_CONFIG: Partial<ProgressConfig> = {
/** CSS3 缓冲动画字符串,支持 ease、linear、ease-in、ease-out、ease-in-out 以及自定义 cubic-bezier 等 */
easing: 'ease',
/** 指定进度条的父容器,默认为 body */
parent: 'body',
/** 是否显示进度条,可通过环境变量控制 */
show: true,
/** 是否显示右侧的环形进度动画 */
showSpinner: false,
/** 是否开启自动递增模式 */
trickle: true,
/** 设置开始时最低百分比,范围 0-1 */
minimum: 0.08,
/** 动画速度,单位毫秒 */
speed: 200,
}
/**
* 进度条控制工具 Hook
* @param config 自定义配置,会与默认配置深度合并
* @returns { start, done } 启动/结束进度条方法
*/
export function useProgress(config: Partial<ProgressConfig> = {}) {
const mergeConfig = merge({}, DEFAULT_CONFIG, config)
NProgress.configure(mergeConfig)
/**
* 启动进度条
*/
function start() {
if (!mergeConfig.show) return
NProgress.start()
}
/**
* 结束进度条
*/
function done() {
if (!mergeConfig.show || !NProgress.isStarted()) return
NProgress.done()
}
return { start, done }
}
三、实际应用场景
3.1 Axios 请求拦截器集成
在实际项目中,我们通常需要为 API 请求自动添加进度条。以下是配合 Axios 使用的完整示例,通过环境变量控制是否显示:
// src/utils/request.ts
import axios, { AxiosInstance, AxiosResponse, InternalAxiosRequestConfig } from 'axios'
const NProgress = useProgress({ show: import.meta.env.VITE_REQUEST_NPROGRESS !== 'false' })
const instance: AxiosInstance = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL,
timeout: 15000,
})
// 请求拦截器
instance.interceptors.request.use(
(config: InternalAxiosRequestConfig) => {
NProgress.start()
return config
},
(error) => {
NProgress.done()
return Promise.reject(error)
},
)
// 响应拦截器
instance.interceptors.response.use(
(response: AxiosResponse) => {
NProgress.done()
return response
},
(error) => {
NProgress.done()
return Promise.reject(error)
},
)
export const request = instance
3.2 Vue Router 路由守卫集成
结合 Vue Router,可以在页面切换时显示进度条,通过环境变量控制是否显示:
// src/router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({
history: createWebHistory(),
routes: [],
})
const NProgress = useProgress({ show: import.meta.env.VITE_ROUTER_NPROGRESS !== 'false' })
router.beforeEach((to, from, next) => {
NProgress.start()
next()
})
router.afterEach(() => {
NProgress.done()
})
export default router
3.3 组合式使用示例
<template>
<div class="app">
<button @click="loadData">加载数据</button>
</div>
</template>
<script setup lang="ts">
import { useProgress } from '@/hooks/useProgress'
const NProgress = useProgress({ show: import.meta.env.VITE_REQUEST_NPROGRESS !== 'false' })
async function loadData() {
NProgress.start()
try {
await fetch('/api/data')
} finally {
NProgress.done()
}
}
</script>
四、全局样式配置
4.1 全局样式入口文件
创建全局样式入口文件,统一管理项目样式:
// src/styles/index.scss
@use './variables.scss';
@use './transition.scss';
@use 'nprogress/nprogress.css';
@use './element-plus/el-table.scss';
@use './element-plus/el-dialog.scss';
@use './element-plus/el-dropdown.scss';
body {
font-family: var(--el-font-family);
background-color: var(--el-bg-color-page);
}
#nprogress .bar {
background-color: var(--el-color-primary);
}
4.2 样式文件说明
- variables.scss:Element Plus 主题变量定义
- transition.scss:全局过渡动画样式
- nprogress.css:NProgress 进度条基础样式
- element-plus/*.scss:Element Plus 组件样式覆盖
- 全局样式:包含进度条颜色等自定义样式
4.3 NProgress 主题样式覆盖
如果需要更详细的自定义 NProgress 样式,可以创建专门的样式文件:
// src/styles/nprogress.scss
#nprogress .bar {
background-color: var(--el-color-primary);
height: 3px;
// 添加渐变效果
background: linear-gradient(90deg, var(--el-color-primary-light-3) 0%, var(--el-color-primary) 100%);
}
#nprogress .peg {
box-shadow: 0 0 10px var(--el-color-primary);
}
#nprogress .spinner-icon {
border-top-color: var(--el-color-primary);
border-left-color: var(--el-color-primary);
}
4.4 在入口文件中引入
// src/styles/index.scss
@use './variables.scss';
@use './transition.scss';
@use './nprogress.scss'; // 替换为自定义样式文件
@use './element-plus/el-table.scss';
@use './element-plus/el-dialog.scss';
@use './element-plus/el-dropdown.scss';
body {
font-family: var(--el-font-family);
background-color: var(--el-bg-color-page);
}
#nprogress .bar {
background-color: var(--el-color-primary);
}
4.5 main.ts 中引入全局样式
// src/main.ts
import { createApp } from 'vue'
import App from './App.vue'
import './styles/index.scss' // 引入全局样式
const app = createApp(App)
app.mount('#app')
五、NProgress 配置详解
5.1 核心配置项
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| easing | string | 'ease' | CSS3 缓动函数 |
| speed | number | 200 | 动画速度(毫秒) |
| trickle | boolean | true | 是否自动递增 |
| trickleSpeed | number | 200 | 自动递增速度 |
| minimum | number | 0.08 | 起始百分比 |
| showSpinner | boolean | false | 是否显示环形动画 |
| showUI | boolean | false | 是否显示进度条 |
| parent | string | 'body' | 父容器选择器 |
| positionUsing | string | '' | 定位方式 |
5.2 缓动函数推荐
const EASING_FUNCTIONS = {
// 匀速运动
linear: 'linear',
// 标准缓动
ease: 'ease',
easeIn: 'ease-in',
easeOut: 'ease-out',
easeInOut: 'ease-in-out',
// 自定义贝塞尔曲线
smooth: 'cubic-bezier(0.4, 0, 0.2, 1)',
gentle: 'cubic-bezier(0.25, 0.1, 0.25, 1)',
swift: 'cubic-bezier(0.4, 0, 0.6, 1)',
}
五、总结
通过本文的学习,你应该已经掌握了:
- 基础集成:如何在 Vue3 项目中安装和配置 NProgress
- 封装技巧:如何封装通用的进度条 Hook,提高代码复用性
- 环境变量控制:如何通过环境变量灵活控制进度条的开关
- 实际应用:如何与 Axios、Vue Router 等常见库配合使用
- 全局样式配置:如何通过全局样式统一管理进度条外观