如何实现页面加载进度条?

羽霏 ☘︎ 阅读 13

我在做项目首页,想加个顶部的加载进度条,但不知道怎么监听整体资源加载进度。

试过用 window.onload,但只能知道什么时候加载完,没法拿到中间的进度。也查了 performance.getEntriesByType('resource'),但感觉拿不到实时百分比啊。

现在用的是 Vue 3 + Vite,有没有办法在路由切换或初始加载时显示一个平滑的进度条?比如像 NProgress 那种,但我想自己实现核心逻辑。

我来解答 赞 12 收藏
二维码
手机扫码查看
1 条解答
上官天朝
说实话,真实的资源加载进度基本拿不到精确值,浏览器的 API 限制就在那。实际项目中大多数进度条都是"假装"在加载,用一个定时器模拟进度,真正加载完了直接跳到 100%。

你用 Vue 3 + Vite 的话,分两个场景处理。

第一个场景是路由切换,这个好办,用 Vue Router 的导航守卫配合一个简单的进度条组件就行。写个简单的实现:

// progress.js
import { ref } from 'vue'

const progress = ref(0)
let timer = null
let isDone = false

export function useProgress() {
const start = () => {
progress.value = 0
isDone = false
timer = setInterval(() => {
if (isDone) return
// 模拟进度,越往后越慢
const increment = Math.random() * 10 * (1 - progress.value / 100)
progress.value = Math.min(95, progress.value + increment)
}, 100)
}

const done = () => {
isDone = true
clearInterval(timer)
progress.value = 100
setTimeout(() => {
progress.value = 0
}, 300)
}

return { progress, start, done }
}


路由守卫里这样用:

// router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import { useProgress } from './progress'

const router = createRouter({ /* 你的路由配置 */ })
const { start, done } = useProgress()

router.beforeEach((to, from, next) => {
start()
next()
})

router.afterEach(() => {
done()
})


第二个场景是首次加载,这个稍微麻烦点。你可以在 index.html 里内联一段 CSS 和 JS,让进度条在 Vue 还没挂载前就显示。Vite 打包后会有一个入口 JS,用 document.readyState 或者监听 load 事件来判断页面加载完成。

有几个安全点要注意。定时器一定要清理,不然内存泄漏,组件销毁时记得 clearInterval。还有进度条组件尽量用固定定位,别让其他元素影响它。如果你用用户输入来控制进度条(虽然不太可能),要做校验,防止恶意注入。

另外,如果你项目里有异步请求依赖,比如路由组件里要 fetch 数据,可以在组件里手动调 start 和 done,配合 Suspense 或者 loading 状态一起用。

基本上这样就能实现一个类似 NProgress 的效果了,代码也不多,自己掌控也更灵活。
点赞
2026-03-02 12:15