Skip to content
uAdmin

路由与导航如何配合 ​

目标:让页面可访问、菜单可发现,并在模块停用或权限变化后保持一致。路由是前端声明,导航是当前用户可用入口,两者分别配置。

三种路由入口 ​

createUAdmin 的类型位于 packages/app/src/types.ts:

配置用途演示位置
modules可随模块启停的业务路由apps/demo/src/modules.ts
routes布局内始终注册的页面apps/demo/src/routes.ts
publicRoutes布局外免登录页面同上

routes 不代表免登录;公开访问必须放进 publicRoutes。不要通过把业务页移到公开路由来绕过导航加载问题。

ts
const reportRoute = {
  path: '/reports',
  name: 'Reports',
  component: () => import('./Reports.vue'),
  meta: { title: 'reports.title', perms: ['report:read'], keepAlive: true },
}

给页面使用稳定且唯一的 name,标签页清理和缓存均依赖路由身份。meta.affix 固定标签,hiddenTag 隐藏标签,hideInMenu 用于静态菜单;它们均不代替权限声明。

后端导航模式 ​

默认 nav: 'backend' 调用 backend.nav()。快照满足 @uadmin/protocol 的 NavSnapshot:

json
{
  "protocolVersion": 1,
  "modules": ["reports"],
  "permissions": ["report:read"],
  "menu": [
    {
      "key": "business",
      "title": "业务",
      "children": [
        {
          "key": "reports",
          "title": "报表",
          "path": "/reports",
          "module": "reports"
        }
      ]
    }
  ]
}

服务端应按用户裁剪菜单,也可以返回 titleKey 交给前端翻译。内核只注册“前端声明过且快照启用”的模块,未知模块不会加载代码。快照权限会覆盖会话中的权限,确保路由和最新授权一致。

首次进入的执行顺序 ​

packages/app/src/guard.ts 先判断登录;没有 token 时转到登录页,并保留 redirect。已有 token 但导航未就绪时,useNavStore().load() 获取快照和必要的用户资料、注册动态路由,然后重新匹配原地址,最后校验 meta.perms。

模块生命周期操作后可调用 await useNavStore().load() 重新同步。旧动态路由先移除,新路由再注册;失效的非固定、命名标签会被清理。模块开关不会删除前端源码,也不会安装后端程序。

静态导航模式 ​

设置 nav: 'static' 后,菜单从模块路由的 meta.title、group、order、icon 等生成,全部前端模块启用,不请求导航快照。用户资料仍来自 backend.me(),路由守卫仍校验权限。

当前静态菜单生成器不按 meta.perms 裁剪菜单;需要按用户展示入口时优先使用后端模式。隐藏菜单只是呈现控制,直接输入 URL 仍由守卫判断。

深链和排障 ​

默认 hash 路由可使用 /demo/#/tasks,静态服务器只需提供 /demo/index.html。选择 history: 'web' 后,必须配置服务器将页面深链回退到应用入口。

有菜单但 404: 核对菜单 path 与路由 path,以及模块名称是否一致。能打开但没有菜单: 检查快照树、父分组和 module 字段。权限修改未生效: 刷新快照,检查最终 permissions,而不是只看角色名称。新增页面还需登记演示的 src/views/page-nav/entries.ts。

Vue 3 · TypeScript · Element Plus