Vue / 闯关模式
Vue 进阶篇:Router Pinia 权限 工程化
把 Vue 用户管理页放进后台项目,补齐 Router、Pinia、权限、接口层和工程化目录。
一句话:Vue 进阶就是把用户管理页放进真实后台系统,让路由、Pinia、权限、接口层和目录结构都能长期维护。
第 7 篇 / 共 12 篇。
本篇学完你会:用 Vue Router、Pinia、TypeScript 和工程化目录组织一个可维护的用户管理模块。
1. 什么叫 Vue 进阶
进阶不是把所有 API 都背下来,而是让页面能进入真实项目。
真实后台要考虑:
路由
布局
权限
全局用户信息
菜单
接口封装
错误处理
目录结构
构建检查
2. Vue Router 怎么组织
路由配置:
import { createRouter, createWebHistory } from 'vue-router';
export const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/admin',
component: () => import('@/layouts/AdminLayout.vue'),
children: [
{
path: 'users',
component: () => import('@/features/users/pages/UserManagementPage.vue'),
meta: {
title: '用户管理',
permission: 'user:read'
}
}
]
}
]
});大白话:路由表不仅能配页面,也能带上权限和标题。
3. 权限路由怎么做
路由守卫:
router.beforeEach((to) => {
const authStore = useAuthStore();
const permission = to.meta.permission as string | undefined;
if (permission && !authStore.permissions.includes(permission)) {
return '/403';
}
return true;
});按钮权限:
<button v-if="authStore.hasPermission('user:create')">新增用户</button>前端权限只负责体验,真正安全必须由后端接口校验。
4. Pinia 放什么状态
Pinia 适合放全局共享状态:
export const useAuthStore = defineStore('auth', {
state: () => ({
user: null as CurrentUser | null,
permissions: [] as string[]
}),
actions: {
setUser(user: CurrentUser) {
this.user = user;
this.permissions = user.permissions;
},
hasPermission(permission: string) {
return this.permissions.includes(permission);
}
}
});不要把所有页面表单都塞进 Pinia。用户编辑弹窗的草稿,放组件本地就够了。
5. 用户管理模块目录
推荐目录:
src/
features/
users/
api.ts
types.ts
composables/
use-users.ts
components/
UserFilter.vue
UserForm.vue
UserTable.vue
pages/
UserManagementPage.vue和 React 线类似,按业务模块聚合,而不是把所有组件扔进一个大 components/。
6. 接口层怎么抽
export type PageResult<T> = {
list: T[];
total: number;
};
export async function fetchUsers(query: UserQuery): Promise<PageResult<User>> {
return request.get('/users', { params: query });
}
export async function saveUser(value: UserFormValue) {
return request.post('/users', value);
}页面和 composable 不应该散落 fetch('/api/xxx'),否则项目大了很难统一处理 token、错误码、刷新登录。
7. TypeScript 怎么收紧
权限码可以定义成联合类型:
export type PermissionCode = 'user:read' | 'user:create' | 'user:update' | 'user:delete';路由 meta 可以扩展类型:
declare module 'vue-router' {
interface RouteMeta {
title?: string;
permission?: PermissionCode;
}
}这样路由里写错权限名,类型检查能帮你提前发现。
8. 性能优化看哪里
Vue 用户管理页常见优化:
| 问题 | 优化 |
|---|---|
| 搜索频繁请求 | debounce |
| 表格很大 | 分页、虚拟列表 |
| 计算统计频繁 | computed |
| 弹窗组件重 | 动态导入 |
| 无关组件更新 | 拆组件、减少全局状态依赖 |
Vue 的响应式已经做了很多优化,先别过早手动优化。
9. 常见错误
| 错误 | 后果 |
|---|---|
| Pinia 放太多局部状态 | 状态难追踪 |
| 路由权限只靠菜单隐藏 | 直接访问 URL 可能进入 |
| 接口层没有统一封装 | token 和错误处理重复 |
| 类型全写 any | Vue + TS 的价值没了 |
| 业务目录不聚合 | 找代码很痛苦 |
10. 下一步怎么学
Vue 线到这里形成闭环:
模板 -> 响应式 -> Composition API -> 请求表单 -> Router -> Pinia -> 权限工程化下一篇建议进入对比线:大白话讲解——React vs Vue 心智模型对比.md