nprogress卡在0%或不消失的根本原因是其默认监听document.readystate等全局事件,而spa中需控制路由切换或api请求完成时机。应在vue router的beforeeach启动、aftereach和onerror收起,并对api请求用inc()/done()手动管理计数器,同时注意dom插入点、样式及css过渡兼容性。

为什么直接用 NProgress 会卡在 0% 或不消失
NProgress 默认依赖 document.readyState 和原生事件(如 DOMContentLoaded、load),但在现代前端项目中,尤其是使用 Webpack/Vite 打包、动态 import、或单页应用(SPA)路由切换时,这些事件无法准确反映「当前页面内容是否加载完成」。常见现象是进度条卡在 0.3 或 0.7 不动,或者跳转后没触发 done(),残留遮罩。
根本原因不是 NProgress 有 bug,而是它默认监听的是 HTML 文档生命周期,而你真正想控制的是「路由切换」或「数据请求完成」这两个更细粒度的时机。
- SPA 中
window.addEventListener('load', ...)只触发一次,后续路由变化不会触发 - 若页面含大量懒加载图片或第三方脚本,
load事件早于内容渲染完成 - NProgress 的
start()和done()必须成对调用,漏掉任意一次都会导致状态错乱
在 Vue Router 中正确触发 NProgress 的位置
对于 Vue 项目,应把 start() 放在全局前置守卫(router.beforeEach),done() 放在全局后置守卫(router.afterEach),但要注意:后置守卫不捕获导航失败(如 404、守卫抛错),所以必须补上错误处理。
router.beforeEach((to, from, next) => {
NProgress.start();
next();
});
<p>router.afterEach(() => {
NProgress.done();
});</p><p>router.onError(() => {
NProgress.done();
});</p>
-
router.beforeEach是唯一可靠触发「开始加载」的位置,不能放在组件内mounted—— 那时路由已跳完,进度条一闪就没了 -
router.afterEach不接收next,只适合做副作用清理;不要在里面调用异步操作(如await api.get()),否则done()会被延迟 - 务必加
router.onError,否则路由守卫中next(false)或未捕获异常会导致进度条永远不收起
如何让 NProgress 在 API 请求期间也显示
单纯靠路由守卫只能覆盖页面跳转,但用户点击按钮触发数据加载(比如搜索、提交表单)时,也需要进度反馈。这时不能复用 NProgress 的全局状态,而应使用它的「递增模式」+ 手动控制。
关键点:NProgress 支持嵌套调用,start() 每调一次,内部计数器 +1;done() 每调一次,-1;只有计数器归零才真正隐藏进度条。
- 封装一个请求函数,在发起前调用
NProgress.inc()(比start()更轻量,避免重复从 0 开始) - 响应成功/失败后都调用
NProgress.done(),确保计数器能清零 - 避免在同一个操作里混用
start()和inc(),它们行为不同:start()强制重置为0.3,inc()是随机微增(如0.3 → 0.35 → 0.42)
示例:
async function fetchUser(id) {
NProgress.inc(); // 不用 start()
try {
const res = await axios.get(`/api/user/${id}`);
return res.data;
} finally {
NProgress.done();
}
}
自定义 NProgress 样式与 DOM 插入点避坑
NProgress 默认把进度条插入到 document.body 最前面,如果页面用了 position: fixed 的顶部导航栏,进度条可能被遮挡。修改插入点需在初始化时指定 parent,且该容器必须存在、可定位、z-index 足够高。
- 不要在
document.body.appendChild(...)后再初始化 NProgress —— 它会在初始化时自己重插 DOM - 推荐写法:
NProgress.configure({ parent: '#app', minimum: 0.15 });,其中#app是你的根容器,且 CSS 中要确保它有position: relative或position: fixed - 修改颜色别直接改 CSS 类名(
.bar),而是用template配置项替换整个 HTML 结构,否则容易因优先级问题失效 -
minimum设太低(如0.01)会导致进度条长时间卡在起点,人眼感知不到变化;设太高(如0.4)会让用户误以为加载很慢
最常被忽略的一点:NProgress 的动画依赖 transition,如果你全局重置了 * { transition: none !important },进度条就会变成瞬移或卡死 —— 这类 CSS 重置必须排除 .nprogress 相关选择器。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











