Files
2026-02-28 15:16:15 +08:00

16 KiB
Raw Permalink Blame History

路由与导航

**本文引用的文件** - [frontend/src/router/index.js](file://frontend/src/router/index.js) - [frontend/src/main.js](file://frontend/src/main.js) - [frontend/src/App.vue](file://frontend/src/App.vue) - [frontend/src/views/Layout.vue](file://frontend/src/views/Layout.vue) - [frontend/src/views/Login.vue](file://frontend/src/views/Login.vue) - [frontend/src/stores/user.js](file://frontend/src/stores/user.js) - [frontend/src/stores/app.js](file://frontend/src/stores/app.js) - [frontend/src/api/menu.js](file://frontend/src/api/menu.js) - [frontend/src/api/request.js](file://frontend/src/api/request.js) - [frontend/src/views/assessment/AssessmentDetail.vue](file://frontend/src/views/assessment/AssessmentDetail.vue) - [frontend/package.json](file://frontend/package.json)

目录

  1. 简介
  2. 项目结构
  3. 核心组件
  4. 架构总览
  5. 详细组件分析
  6. 依赖关系分析
  7. 性能考虑
  8. 故障排查指南
  9. 结论
  10. 附录

简介

本文件系统化梳理了 Vue Router 在本项目中的路由管理实践,覆盖路由配置、嵌套路由、动态路由、路由守卫与权限拦截、参数传递与查询字符串处理、路由元信息、面包屑与侧边栏联动、页面标题动态更新、懒加载与代码分割、登录态保持与权限控制、以及页面缓存策略等主题。旨在帮助开发者快速理解并扩展路由体系。

项目结构

前端采用 Vite + Vue 3 + vue-router 4 + Pinia 的现代前端栈,路由集中于 router/index.js视图组件位于 views 下,状态管理位于 storesHTTP 请求封装于 api/request.js 并通过 axios 实现拦截器。

graph TB
A["入口 main.js"] --> B["应用 App.vue"]
A --> C["路由 router/index.js"]
C --> D["布局 Layout.vue"]
D --> E["侧边栏菜单<br/>动态加载"]
D --> F["面包屑<br/>基于 meta.title"]
D --> G["主内容区 router-view"]
G --> H["各业务视图<br/>如 Login.vue / Dashboard.vue / AssessmentDetail.vue"]
A --> I["状态 stores<br/>user.js / app.js"]
A --> J["HTTP 封装 api/request.js"]

图表来源

章节来源

核心组件

  • 路由定义与守卫:集中于 router/index.js包含基础路由、嵌套路由、动态路由、全局前置守卫。
  • 应用入口与挂载main.js 完成插件注册、路由挂载与国际化配置。
  • 布局与导航Layout.vue 提供侧边栏菜单、面包屑、头部用户信息与内容区过渡动画。
  • 登录与权限Login.vue 负责登录交互user.js 管理 token 与登录态;全局守卫进行未登录拦截。
  • 状态管理app.js 管理侧边栏折叠与部门树user.js 管理用户信息与登出跳转。
  • HTTP 封装request.js 统一添加 Authorization 头、处理 401/403/404/500 等响应错误并重定向到登录。

章节来源

架构总览

路由层负责页面级导航与权限控制;布局层负责 UI 结构与导航元素状态层负责登录态与侧边栏状态HTTP 层统一处理鉴权头与错误响应。

sequenceDiagram
participant U as "用户"
participant R as "路由守卫<br/>router.beforeEach"
participant L as "登录页<br/>Login.vue"
participant S as "状态 stores<br/>user.js"
participant M as "主布局<br/>Layout.vue"
U->>R : 访问任意受保护路由
R->>R : 读取 localStorage.token
alt 未登录且非 /login
R-->>U : 重定向至 /login
else 已登录或访问 /login
R-->>M : 放行并渲染布局
end
U->>L : 输入凭据并提交
L->>S : 调用 userStore.login(...)
S-->>L : 成功则写入 token 并跳转 /
L-->>M : 渲染主布局

图表来源

详细组件分析

路由配置与嵌套路由

  • 基础路由:登录页与根路径重定向。
  • 嵌套路由:根路径下包含 dashboard、基础数据、考核、工资、报表、财务、计划、系统管理等模块系统管理内部再嵌套菜单管理。
  • 路由元信息:每个路由配置了 meta.title、icon 等,用于面包屑与侧边栏展示。
  • 默认重定向:访问根路径时自动跳转到 dashboard。

章节来源

动态路由与菜单联动

  • 后端菜单树:通过 api/menu.js 的 getMenuTree 接口拉取菜单树,转换为前端可用的菜单项数组。
  • 侧边栏渲染Layout.vue 中根据 menuItems 渲染 el-menu支持折叠与图标显示。
  • 回退菜单:若拉取失败,使用默认菜单作为后备,保证可用性。

章节来源

动态路由参数与详情页

  • 动态路由:/assessments/:id 对应 AssessmentDetail 页面。
  • 参数读取:在 AssessmentDetail.vue 中通过 useRoute().params.id 获取动态参数。
  • 查询字符串:当前示例未使用查询参数,但可通过 useRoute().query 获取。

章节来源

路由元信息与面包屑

  • 元信息:每个路由的 meta.title 用于页面标题与面包屑显示。
  • 面包屑Layout.vue 中直接使用 route.meta.title 作为当前面包屑文本。
  • 页面标题:全局守卫在每次导航前设置 document.title。

章节来源

路由守卫、权限验证与导航拦截

  • 全局前置守卫router.beforeEach 读取 token未登录且访问非 /login 路由时强制跳转登录。
  • 登录成功Login.vue 调用 userStore.login成功后写入 token 并跳转根路径。
  • 登出user.js 中 logout 清空 token 并跳转 /login。
  • HTTP 层拦截request.js 在 401 时清除 token 并跳转 /login确保前后端一致。
flowchart TD
Start(["进入 beforeEach"]) --> ReadToken["读取 localStorage.token"]
ReadToken --> IsLogin{"是否已登录?"}
IsLogin --> |是| Next["放行 next()"]
IsLogin --> |否| IsLoginPage{"是否访问 /login"}
IsLoginPage --> |是| Next
IsLoginPage --> |否| ToLogin["next('/login')"]
Next --> End(["结束"])
ToLogin --> End

图表来源

章节来源

页面标题动态更新

  • 标题来源:全局守卫根据 to.meta.title 设置 document.title并附加系统名。
  • 建议:可在路由 meta 中补充更完整的标题链路,便于多级标题展示。

章节来源

面包屑导航与侧边栏菜单

  • 面包屑Layout.vue 使用 route.meta.title 显示当前页面标题。
  • 侧边栏Layout.vue 通过 api/menu.js 拉取菜单树,渲染 el-menu支持折叠与图标。
  • 菜单回退:若接口异常,使用默认菜单保障可用性。

章节来源

页面缓存机制

  • 当前实现Layout.vue 使用 包裹并配合过渡动画,未见显式 keep-alive 缓存策略。
  • 建议:对频繁切换但无需刷新的页面(如列表页)可引入 keep-alive 以提升体验。

章节来源

登录状态保持与权限控制

  • 登录态token 存储于 localStorageuser.js 提供 login/getUserInfo/logout。
  • 权限控制:全局守卫 + HTTP 401 自动登出,确保未授权访问被拦截。
  • 用户信息userStore.getUserInfo 用于初始化用户信息,但当前布局未消费该数据。

章节来源

路由懒加载与代码分割

  • 路由级懒加载:各路由 component 使用函数返回动态 import实现按需加载与代码分割。
  • 性能收益:首屏仅加载必要模块,减少初始包体积。

章节来源

查询字符串处理

  • 当前路由未使用查询参数示例;如需使用,可在组件中通过 useRoute().query 获取。
  • 建议:对需要持久化的筛选条件,优先使用查询参数,利于分享与刷新恢复。

章节来源

依赖关系分析

  • 路由依赖router/index.js 依赖 Vue Router 与本地组件;全局守卫依赖 localStorage。
  • 视图依赖Layout.vue 依赖 stores 与 api/menu.jsLogin.vue 依赖 stores/user.js 与 router。
  • 状态依赖user.js 依赖 api/auth 与 routerapp.js 依赖 api/department。
  • HTTP 依赖api/request.js 依赖 axios并向 router 注入 401 自动登出逻辑。
graph LR
R["router/index.js"] --> V1["views/Login.vue"]
R --> V2["views/Layout.vue"]
V2 --> S1["stores/user.js"]
V2 --> S2["stores/app.js"]
V2 --> A1["api/menu.js"]
V1 --> S1
S1 --> A2["api/auth (未在仓库中)"]
A1 --> A3["后端 /menus* 接口"]
R --> R2["全局守卫使用 localStorage"]
R --> A4["api/request.js"]

图表来源

章节来源

性能考虑

  • 路由懒加载:已通过动态 import 实现按需加载,建议结合路由级命名与路由表拆分进一步优化打包。
  • 过渡动画Layout.vue 已启用淡入淡出过渡,避免白屏与闪烁。
  • 首屏优化:将高频但非首屏使用的路由组件继续延迟加载,减少首屏 JS 体积。
  • 缓存策略:对列表类页面引入 keep-alive减少重复渲染与请求开销。
  • 图标与第三方库Element Plus 图标已全局注册,避免重复导入。

章节来源

故障排查指南

  • 无法进入受保护页面
    • 检查 localStorage 是否存在 token确认全局守卫逻辑与路由路径匹配。
  • 登录后未跳转
    • 检查 Login.vue 中调用 userStore.login 返回值与 router.push('/') 执行。
  • 401 自动登出后未回到登录页
    • 检查 request.js 响应拦截器是否正确清除 token 并跳转 /login。
  • 面包屑不显示
    • 确认目标路由 meta.title 是否配置Layout.vue 是否使用 route.meta.title。
  • 侧边栏菜单为空
    • 检查 api/menu.js 接口返回结构与 Layout.vue 转换逻辑;关注异常回退分支。

章节来源

结论

本项目的路由体系以简洁清晰的方式实现了基础导航、嵌套与动态路由、全局守卫与权限拦截、元信息驱动的面包屑与标题、以及基于懒加载的代码分割。后续可在菜单树结构、页面缓存策略、查询参数与面包屑链路等方面进一步增强,以满足更复杂的业务场景与用户体验需求。

附录

  • 技术栈版本参考
    • Vue 3、Vue Router 4、Pinia、Element Plus、Axios、Vite
  • 建议的后续改进方向
    • 菜单树结构标准化与权限位映射
    • 面包屑链路与路由层级联动
    • 页面级 keep-alive 缓存策略
    • 查询参数与路由参数的规范使用

章节来源