推荐使用 Pinia 定义带计数器的 loading store,通过 count 增减和 computed 控制 isLoading,并结合 $onAction 自动注入 loading 逻辑,实现按业务粒度精准控制、异常安全、可扩展的页面级 Loading 管理。

在 Vue 3 的 script setup 中管理页面级 Loading 状态,关键不是每个组件都手写 ref(false) 和 try/finally,而是把状态逻辑收口、复用、解耦。推荐以“状态驱动 UI”为原则,结合 Pinia + 按需控制,避免全局遮罩一刀切,也规避布尔值误关风险。
用 Pinia 定义带计数器的 loading store
这是最健壮、可扩展的方案,尤其适合中大型项目:
- state 中定义
count: number = 0和计算属性isLoading: boolean(computed(() => count > 0)) - 提供
showLoading()(count++)和hideLoading()(count--,仅当count === 0时才设为 false) - 组件中直接使用:
const loadingStore = useLoadingStore(),模板里绑定v-loading="loadingStore.isLoading"(Element Plus)或v-if="loadingStore.isLoading"(自定义遮罩)
按业务动作粒度控制,不干扰其他操作
全屏 loading 往往太重。更合理的是区分场景:
从零开始编排 SpringBoot+Vue 全栈项目工作流,适用于新建全栈项目或完整脚手架请求,触发后依次调用 product‑spec‑builder(需求调研)等模块。
- 在 store 中用对象管理:例如
loading: { userList: false, userDetail: false, formSubmit: false } - 组件调用对应 action 时显式控制字段:
userStore.fetchList(); // 内部自动 this.loading.userList = true → finally → false - 模板中精准响应:
:disabled="userStore.loading.formSubmit"控按钮,v-loading="userStore.loading.userList"控表格,v-if="userStore.isAnyLoading"控全局遮罩层
用 $onAction 自动注入 loading 逻辑(免手写 try/finally)
Pinia 的 $onAction 钩子能统一拦截异步 action,大幅减少样板代码:
立即学习“前端免费学习笔记(深入)”;
- 在 store 创建后注册:
this.$onAction(({ name, after, onError }) => { if (name.includes('fetch') || name.includes('submit')) { this.showLoading() } after(() => this.hideLoading()) onError(() => this.hideLoading()) }) - 支持关键词匹配、参数类型守卫(如只对
{ immediate: true }的 action 开启 loading) - 配合
Promise.finally或try/finally,确保异常也不漏关
轻量替代:组合式函数封装 loading 状态(适合小项目或临时需求)
若暂不引入 Pinia,可用 defineComponent 或独立 composable:
- 新建
usePageLoading.ts,返回{ isLoading, show, hide },内部用ref+ 计数器 - 在页面
script setup中调用:const { isLoading, show, hide } = usePageLoading() - 请求时
show(),then/catch/finally 中hide();也可配合watch监听关键 ref 变化自动触发

















