Vuex/Pinia 的核心价值在于统一管理用户权限与侧边栏等跨组件状态,采用结构化存储(roles、permissions、menuList),通过 getter 派生过滤菜单与权限校验,解耦 UI 状态与权限逻辑,并协同 Router 实现动态路由与守卫控制。

在后台系统中,Vuex(或 Pinia)的核心价值之一,就是把用户权限和侧边栏这类跨组件、强关联、需持久化又需响应式更新的状态,统一收口管理。不是简单存个 role 字符串,而是构建一套可扩展、可追踪、与路由和 UI 协同工作的状态结构。
权限数据的结构化存储
权限不应只存一个字符串(如 "admin"),而应是结构化对象,包含角色标识、菜单权限列表、按钮级操作码等。推荐在 Vuex store 中定义 user 模块:
- state 中存放 roles(字符串数组,如 ["admin", "editor"])、permissions(按钮级权限码集合,如 ["user:add", "order:delete"])、menuList(前端预置或后端返回的完整菜单树)
- 登录成功后,通过 action 发起请求获取权限数据,并 commit 到 state;避免直接用 localStorage 存原始权限,防止篡改或过期
- 使用 getter 派生出常用计算值,例如
canAccess('user:list')或filteredMenuList,让组件调用更语义化
侧边栏状态与菜单渲染解耦
侧边栏是否折叠、主题色、当前激活菜单项,这些属于 UI 状态;而“该显示哪些菜单项”,则取决于权限。两者要分离但协同:
从零开始编排 SpringBoot+Vue 全栈项目工作流,适用于新建全栈项目或完整脚手架请求,触发后依次调用 product‑spec‑builder(需求调研)等模块。
- 单独建一个 sidebar 模块管理折叠状态、颜色配置等,支持 localStorage 持久化(如 collapse: false)
- 菜单数据本身来自 user 模块的 menuList,但渲染前需经权限过滤——不是在模板里 v-if 写一堆判断,而是在 getter 中完成:遍历 menuList,递归剔除无权限项,同时自动清理空子菜单(比如子项全被过滤,父项也不显示)
- 组件中只需
v-for="menu in $store.getters.filteredMenuList",逻辑干净,复用性强
与 Vue Router 的联动机制
权限控制最终要落地到路由访问,Vuex 需和 router 协同工作:
立即学习“前端免费学习笔记(深入)”;
- 登录后,根据权限动态生成可访问路由表(addRoutes 或 addRoute),这个路由表可缓存在 Vuex 的 user 模块中,供后续导航守卫或菜单渲染复用
- 全局前置守卫中检查 to.meta.roles,对比 $store.state.user.roles,无权限则跳转 403 或首页
- 避免硬编码路由权限字段,统一约定 meta 字段结构,例如:
meta: { roles: ['admin'], permissions: ['report:view'] }
按钮级权限的轻量封装
页面内按钮显隐、禁用,不建议每个都写 v-if="$store.state.user.permissions.includes('xxx')":
- 封装一个全局指令
v-permission,接收权限码字符串或数组,在 bind 钩子中读取 store 权限并控制 display 或 disabled - 或提供一个组合式函数
usePermission()(Vue 3 + Pinia 下更自然),返回hasPermission(code)方法,便于逻辑判断 - 关键点:权限校验必须走 store 状态,而非本地变量或 props,确保响应式更新时 UI 自动同步

















