Vue / 已完成

Vue 进阶篇:Router Pinia 权限 工程化

把 Vue 用户管理页放进后台项目,补齐 Router、Pinia、权限、接口层和工程化目录。

返回文章积累

一句话:Vue 进阶就是把用户管理页放进真实后台系统,让路由、Pinia、权限、接口层和目录结构都能长期维护。

第 7 篇 / 共 12 篇。

本篇学完你会:用 Vue Router、Pinia、TypeScript 和工程化目录组织一个可维护的用户管理模块。

1. 什么叫 Vue 进阶

进阶不是把所有 API 都背下来,而是让页面能进入真实项目。

真实后台要考虑:

路由
布局
权限
全局用户信息
菜单
接口封装
错误处理
目录结构
构建检查

Vue 后台工程化结构图

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 和错误处理重复
类型全写 anyVue + TS 的价值没了
业务目录不聚合找代码很痛苦

10. 下一步怎么学

Vue 线到这里形成闭环:

模板 -> 响应式 -> Composition API -> 请求表单 -> Router -> Pinia -> 权限工程化

下一篇建议进入对比线:大白话讲解——React vs Vue 心智模型对比.md