ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Fantastic-admin 路由生成器实战:从路由文件到导航菜单、权限与保活的完整配置指南

Fantastic-admin 路由生成器实战:从路由文件到导航菜单、权限与保活的完整配置指南 前端AI 技能【免费下载链接】basic⭐⭐⭐⭐⭐ 面向 AI 编程的管理系统框架兼容PC、移动端。AI-oriented management system framework, compatible with PC and mobile device.项目地址https://gitcode.com/GitHub_Trending/ba/basic点击查看免费下载本篇技术指南以 Fantastic-admin 框架的路由生成器技能skills/fa-route-generator/SKILL.md为骨架系统讲解如何在该框架中创建、修改路由配置并通过meta元信息驱动导航菜单、权限控制、页面保活与面包屑展示。读完本文你将掌握路由文件的标准写法、RouteMetaRaw全部可用属性、列表-详情页保活等高频实战方案以及这些配置在框架源码中的真实生效链路。一、路由生成器是什么一条路由配置驱动整站导航Fantastic-admin 是一个面向 AI 编程的管理系统框架兼容 PC 与移动端仓库采用 monorepo 架构apps/目录下存放各应用如core、example、core-ant-design-vue等。框架的核心设计之一是导航菜单由路由配置自动生成——你不需要单独维护菜单数据只要按照约定编写路由文件并配置meta属性侧边栏菜单、标签页、面包屑、权限过滤与页面保活都会随之联动。这意味着路由配置是整个应用导航体系的单一数据源而路由生成器fa-route-generator就是围绕这一机制提供的操作规范它规定了创建新路由、修改现有路由的完整流程并明确了meta中每个属性的含义与取值。二、前置准备确认目标应用与路由驱动模式第一步确认工作区必须等待用户明确回复由于是 monorepo 架构在执行任何文件读写之前必须先确认要在哪个应用中操作路由。操作规范要求执行ls apps/列出所有可用应用向用户提问明确询问在哪个应用中操作路由并停止等待回复收到明确回复后才能继续。严格规则如果用户没有在请求中明确说明目标应用例如在 example 应用中、apps/core则必须提问不得自行猜测或默认选择任何应用。确认后后续所有文件路径均以该应用目录为根例如apps/app/src/router/。第二步检查路由驱动模式routeBaseOn读取apps/app/src/settings.ts检查app.routeBaseOn的值frontend默认可以继续手动创建的路由文件生效backend路由由后端驱动手动创建的路由文件会被忽略此时应告知用户该模式不支持前端路由文件生成。以apps/core为例其 settings.ts 内容为空未显式配置因此采用默认值。从源码看默认值定义于 packages/settings/src/default.tsrouteMode: hash, routeBaseOn: frontend,而 packages/settings/src/types.ts 中定义的完整取值是frontend | backend | filesystem其中历史遗留的filesystem会在配置解析时被统一映射为frontend见 packages/settings/src/utils.ts。该模式在运行时如何生效查看路由守卫 apps/core/src/router/guards.ts 可知switch (appSettingsStore.settings.app.routeBaseOn) { case frontend: appRouteStore.generateRoutesAtFront(asyncRoutes) break case backend: await appRouteStore.generateRoutesAtBack() break }前端模式直接使用routes.ts中导出的asyncRoutes生成并注册动态路由后端模式则调用 API 获取路由数据后再格式化注册见 apps/core/src/store/modules/app/route.ts。三、框架约定路由文件必须遵守的规则一级路由path必须以/开头component必须是Layout即/layouts/index.vue子路由path不要以/开头多级路由的中间层级无需设置component所有路由的name必须全局唯一。其中多级路由中间层级无需设置 component不仅是约定更是框架的强制处理逻辑。在 apps/core/src/store/modules/app/route.ts 中deleteMiddleRouteComponent会递归删除所有含children的中间层级路由的componentfunction deleteMiddleRouteComponent(routes: RouteRecordRaw[]) { const res: RouteRecordRaw[] [] routes.forEach((route) { if (route.children?.length) { delete route.component route.children deleteMiddleRouteComponent(route.children) } else { delete route.children } res.push(route) }) return res }这一处理在generateRoutesAtFront与systemRoutes计算属性中都会被调用因此即使你在路由文件中给中间层级写了component最终注册时也会被清理。四、场景 A创建新路由1. 收集路由信息向用户询问或确认路由路径、页面标题、图标可选、是否多级路由、所属主导航分组。2. 创建路由文件在apps/app/src/router/modules/下创建模块名.ts例如example.tsimport type { RouteRecordRaw } from vue-router function Layout() { return import(/layouts/index.vue) } const routes: RouteRecordRaw { path: /example, component: Layout, name: example, meta: { title: 示例, icon: i-ep:menu, }, children: [ { path: , name: exampleIndex, component: () import(/views/example/index.vue), meta: { title: 示例页面, }, }, ], } export default routes仓库中真实的路由模块可参考 apps/core/src/router/modules/multilevel.menu.example.ts它演示了三级导航的标准写法顶层component: Layout中间层级level2只写meta与children不写component叶子节点才声明页面组件。3. 更新 routes.ts 并注册到主导航分组在apps/app/src/router/routes.ts中添加 import并把路由模块注册到对应主导航分组的children数组中。以apps/core的 routes.ts 为例import type { RouteRecordMainRaw } from fantastic-admin/types import type { RouteRecordRaw } from vue-router import pinia from /store import MultilevelMenuExample from ./modules/multilevel.menu.example // 动态路由异步路由、导航菜单路由 const asyncRoutes: RouteRecordMainRaw[] [ { meta: { title: 演示, icon: i-ri:function-ai-line, }, children: [ MultilevelMenuExample, ], }, ] export { asyncRoutes, constantRoutes, systemRoutes, }可以看到主导航分组的类型是RouteRecordMainRaw它本身没有path与component只承载metaauth、title、icon、sort与childrenpackages/types/types.ts真正的路由路径由 children 中的路由模块提供。constantRoutes固定路由与systemRoutes系统路由与此并列导出最终constantRoutes在 apps/core/src/router/index.ts 中交给createRouterasyncRoutes由守卫动态注册。五、场景 B修改现有路由定位路由文件在apps/app/src/router/modules/下搜索读取后按需修改meta属性。权限控制meta: { auth: user:view } // 或数组 [user:view, user:edit]auth为字符串时表示需要该权限为数组时表示满足其中一个即可。菜单生成时会据此过滤无权限的导航项见下文权限过滤。页面保活从详情返回列表时保留列表状态// 列表页 meta: { keepAlive: [productDetail] } // 详情页 meta: { menu: false, activeMenu: /product, noKeepAlive: productList }列表页声明keepAlive: [productDetail]只有从名为productDetail的页面返回时才保留列表状态详情页声明menu: false不出现在导航中activeMenu: /product让详情页仍高亮产品管理菜单noKeepAlive: productList表示从列表进入详情时不保活保证详情始终加载最新数据。隐藏菜单项meta: { menu: false, activeMenu: /parent/path }某些页面如详情页、个人设置不需要出现在导航菜单中可用menu: false隐藏同时用activeMenu指定进入该页面时应该高亮的菜单地址。六、RouteMeta 属性全解析框架在 packages/types/types.ts 中定义了RouteMetaRaw接口并通过 packages/types/global.d.ts 将其合并进 vue-router 的RouteMeta因此所有路由meta都能获得完整的类型提示。详细说明见 skills/fa-route-generator/references/route-meta.md。权限相关auth类型string | string[]默认值undefined说明路由访问权限配置为数组时只需满足一个即可进入示例auth: news:view // 需要具备 news:view 权限 auth: [news:view, news:edit] // 需要具备其中一个权限导航显示title必需类型string | (() string)默认值undefined说明标题会在导航、标签页、面包屑等需要的展示位置显示示例title: 新闻管理 title: () 动态标题 // 支持函数式动态标题icon类型string默认值undefined说明导航菜单、标签页等展示区域使用的图标Iconify 图标格式示例icon: i-ep:lock // 默认显示 i-ep:lock 图标menu类型boolean默认值true说明是否在导航中显示当子导航里没有可展示的导航时会直接显示父导航activeMenu类型string默认值undefined说明高亮导航需要设置完整路由地址示例activeMenu: /news/listexpand类型boolean默认值undefined实际表现为不默认展开说明是否默认展开示例expand: true // 默认展开breadcrumb类型boolean默认值true说明是否在面包屑中显示页面行为keepAlive类型boolean | string | string[]默认值undefined说明保活根据规则保活当前路由页面示例keepAlive: true // 始终保活 keepAlive: news // 访问路由name为news的页面时保活 keepAlive: [news, user] // 访问路由name为news或user的页面时保活noKeepAlive类型string | string[]默认值undefined说明不保活根据规则不保活当前路由页面示例noKeepAlive: news // 访问路由name为news的页面时不保活 noKeepAlive: [news, user] // 访问路由name为news或user的页面时不保活link类型string默认值undefined说明外部链接会在浏览器新窗口访问该链接示例link: https://example.com // 在浏览器新窗口打开该外部地址其他源码补充RouteMetaRaw中还包含两个未在技能文档中展开的属性sort导航排序数字越大越靠前默认值0。它由 apps/core/src/store/modules/app/route.ts 的sortAsyncRoutes递归应用到每层路由copyright是否显示版权不设置时使用全局配置。技能文档开篇强调的常用属性即title必需、icon、menu、auth、keepAlive、activeMenu、breadcrumb其余属性按需使用即可。七、高频场景配置示例以下示例均整理自 skills/fa-route-generator/references/examples.md可直接复制到apps/app/src/router/modules/下按需修改。单页面路由最简单的单页面路由配置import type { RouteRecordRaw } from vue-router function Layout() { return import(/layouts/index.vue) } const routes: RouteRecordRaw { path: /dashboard, component: Layout, name: dashboard, meta: { title: 仪表盘, icon: i-ep:data-line, }, children: [ { path: , name: dashboardIndex, component: () import(/views/dashboard/index.vue), meta: { title: 数据概览, }, }, ], } export default routes注意子路由path: 表示该页面直接渲染在父级路径/dashboard上。列表-详情路由最常见的列表与详情页组合const routes: RouteRecordRaw { path: /article, component: Layout, name: article, meta: { title: 文章管理, icon: i-ep:document, }, children: [ { path: , name: articleList, component: () import(/views/article/list.vue), meta: { title: 文章列表, keepAlive: articleDetail, // 从详情返回时保持列表状态 }, }, { path: detail/:id?, name: articleDetail, component: () import(/views/article/detail.vue), meta: { title: 文章详情, menu: false, // 不在导航中显示 activeMenu: /article, // 高亮文章管理菜单 keepAlive: true, noKeepAlive: articleList, // 从列表进入时不保活 }, }, ], }其中path: detail/:id?中?表示id参数可选详情页无需重复注册为独立菜单。二级菜单const routes: RouteRecordRaw { path: /system, component: Layout, name: system, meta: { title: 系统管理, icon: i-ep:setting, }, children: [ { path: user, name: systemUser, component: () import(/views/system/user/index.vue), meta: { title: 用户管理, icon: i-ep:user, }, }, { path: role, name: systemRole, component: () import(/views/system/role/index.vue), meta: { title: 角色管理, icon: i-ep:avatar, }, }, { path: permission, name: systemPermission, component: () import(/views/system/permission/index.vue), meta: { title: 权限管理, icon: i-ep:lock, }, }, ], }三级菜单const routes: RouteRecordRaw { path: /content, component: Layout, name: content, meta: { title: 内容管理, icon: i-ep:folder, }, children: [ { path: article, name: contentArticle, meta: { title: 文章管理, icon: i-ep:document, }, // 注意: 多级路由的中间层级不需要设置 component children: [ { path: list, name: contentArticleList, component: () import(/views/content/article/list.vue), meta: { title: 文章列表, }, }, { path: category, name: contentArticleCategory, component: () import(/views/content/article/category.vue), meta: { title: 文章分类, }, }, ], }, { path: media, name: contentMedia, meta: { title: 媒体管理, icon: i-ep:picture, }, children: [ { path: image, name: contentMediaImage, component: () import(/views/content/media/image.vue), meta: { title: 图片管理, }, }, { path: video, name: contentMediaVideo, component: () import(/views/content/media/video.vue), meta: { title: 视频管理, }, }, ], }, ], }带权限的路由const routes: RouteRecordRaw { path: /admin, component: Layout, name: admin, meta: { title: 管理员, icon: i-ep:user-filled, auth: admin, // 需要 admin 权限 }, children: [ { path: users, name: adminUsers, component: () import(/views/admin/users.vue), meta: { title: 用户列表, auth: [admin:view, admin:edit], // 需要其中一个权限 }, }, ], }外部链接const routes: RouteRecordRaw { path: /external, component: Layout, name: external, meta: { title: 外部链接, icon: i-ep:link, }, children: [ { path: github, name: externalGithub, component: () import(/views/external/link.vue), meta: { title: GitHub, link: https://example.com, // 在新窗口打开外部地址 }, }, ], }默认展开的路由const routes: RouteRecordRaw { path: /menu, component: Layout, name: menu, meta: { title: 菜单示例, icon: i-ep:menu, expand: true, // 默认展开 }, children: [ { path: always, name: menuAlways, meta: { title: 默认展开, expand: true, }, children: [ { path: item1, name: menuAlwaysItem1, component: () import(/views/menu/item1.vue), meta: { title: 菜单项 1, }, }, ], }, ], }八、路由配置调整从改一行 meta 到完整落地权限配置调整场景 1添加单个权限// 修改前 meta: { title: 用户管理, } // 修改后 meta: { title: 用户管理, auth: user:view, // 需要 user:view 权限 }场景 2添加多个权限或关系meta: { title: 用户管理, auth: [user:view, user:edit], // 满足其中一个即可 }页面保活配置场景 1列表页保活——列表页需要在从详情页返回时保持状态{ path: , name: orderList, component: () import(/views/order/list.vue), meta: { title: 订单列表, keepAlive: [orderDetail, orderEdit], // 从这些页面返回时保活 }, }场景 2详情页保活——详情页需要保活但从列表页进入时不保活确保显示最新数据{ path: detail/:id, name: orderDetail, component: () import(/views/order/detail.vue), meta: { title: 订单详情, menu: false, activeMenu: /order, keepAlive: true, // 始终保活 noKeepAlive: orderList, // 从列表进入时不保活 }, }场景 3取消保活——某些页面不需要保活每次进入都重新加载// 删除或注释掉 keepAlive 相关配置 meta: { title: 实时数据, // keepAlive: true, // 删除此行 }导航显示调整隐藏导航项——某些页面如个人设置不需要出现在导航菜单中meta: { title: 个人设置, menu: false, // 不在导航中显示 activeMenu: /user, // 但高亮用户菜单 }面包屑配置场景 1隐藏面包屑meta: { title: 登录, breadcrumb: false, // 不显示面包屑 }场景 2自定义面包屑高亮meta: { title: 编辑文章, activeMenu: /article/list, // 面包屑高亮到文章列表 }在 routes.ts 中的完整注册import ArticleRoute from ./modules/article import ContentRoute from ./modules/content // 1. 导入路由模块 import DashboardRoute from ./modules/dashboard import SystemRoute from ./modules/system // 2. 添加到 asyncRoutes const asyncRoutes: Route.recordMainRaw[] [ { meta: { title: 工作台, icon: i-ep:monitor, }, children: [ DashboardRoute, ], }, { meta: { title: 内容, icon: i-ep:document, }, children: [ ArticleRoute, ContentRoute, ], }, { meta: { title: 系统, icon: i-ep:setting, }, children: [ SystemRoute, ], }, ]九、底层原理路由如何变成菜单、权限与保活如何生效1. 菜单自动生成菜单并非独立维护而是由路由实时转换而来。apps/core/src/store/modules/app/menu.ts 中的convertRouteToMenu把主导航分组转换成MenuRecordMainRawconvertRouteToMenuRecursive递归展开每层路由并只挑选菜单需要的 meta 字段auth、title、icon、menu、expand、link。这也解释了为什么menu: false、expand: true会直接影响导航展示而keepAlive等页面行为属性则不会出现在菜单数据结构中。2. 权限过滤apps/core/src/store/modules/app/menu.ts 的filterAsyncMenus会基于auth.auth(menu.meta?.auth)递归过滤菜单父级无权限则整组移除子级全部无权限的父级也不会展示。同时路由守卫 apps/core/src/router/guards.ts 中的setupRedirectAuthChildrenRoute会在父级路由未配置重定向时自动重定向到第一个有访问权限且menu ! false的子路由保证无权限用户不会落到空白页。3. 保活机制保活由路由守卫 apps/core/src/router/guards.ts 的setupKeepAlive驱动规则与文档完全一致to.meta.keepAlive为boolean时不为true则清除保活为string时与from.name不一致则清除保活为array时不包含from.name则清除保活to.meta.noKeepAlive为string且与from.name一致或为array且包含from.name则清除保活从reload页面刷新进入时清除保活。清除或添加操作最终落到 apps/core/src/store/modules/app/keepAlive.ts 的appKeepAliveStoreadd/remove/clean由布局中的KeepAlive组件消费。另外需要注意保活依赖组件name若组件未命名开发环境下会通过warnKeepAliveComponentNameMissing给出警告提示。4. 路由注册与守卫apps/core/src/router/guards.ts 的setupRoutes是核心守卫登录后先可选拉取用户权限再按routeBaseOn模式生成动态路由并通过router.addRoute注册同时记录removeRoutes回调供登出时清理。此外框架还扩展了 vue-router 的能力apps/core/src/router/extensions.ts为router增加了back关闭当前标签页并回退/跳转与close关闭当前标签页并跳转等扩展语法与标签页功能联动。路由模式hash / history则由settings.app.routeMode控制apps/core/src/router/index.ts。十、小结Fantastic-admin 的路由体系以约定优于配置为原则写好modules/下的路由文件、遵守路径与组件约定、按需配置meta即可自动获得导航菜单、权限控制、页面保活、面包屑与标签页等完整能力。实操时可遵循以下 Checklist先确认目标应用monorepo 下不得猜测与routeBaseOn是否为frontend新建路由在apps/app/src/router/modules/创建模块文件 → 在routes.ts注册到主导航分组修改路由直接调整meta优先使用auth/menu/activeMenu/keepAlive/noKeepAlive/breadcrumb等高频属性牢记框架约定一级路由以/开头且挂载Layout、子路由不带/、中间层级不写component、name全局唯一遇到保活、权限、菜单展示问题可回查 guards.ts 与 menu.ts 的判定逻辑理解配置背后的真实执行规则。赞分享前端AI 技能【免费下载链接】basic⭐⭐⭐⭐⭐ 面向 AI 编程的管理系统框架兼容PC、移动端。AI-oriented management system framework, compatible with PC and mobile device.项目地址https://gitcode.com/GitHub_Trending/ba/basic点击查看免费下载相关推荐Roc 模式匹配的基石work-list 算法实现类型 inhabitedness 检查的原理与源码解析Roc 模式匹配的基石work list 算法实现类型 inhabitedness 检查的原理与源码解析 本篇技术文章围绕 Roc 编译器耗尽性检查exha前端AI 技能Fantastic-admin 路由配置示例详解从单页面到多级菜单的完整实战指南Fantastic admin 路由配置示例详解从单页面到多级菜单的完整实战指南 导读 本文以 Fantastic admin ba/basic 仓库的路前端AI 技能v3-admin-vite路由配置完全指南动态路由与菜单生成v3 admin vite路由配置完全指南动态路由与菜单生成 引言路由管理的痛点与解决方案 你是否在开发后台管理系统时遇到过以下问题权限控制繁琐、菜单与路前端上一篇成为 Apache DolphinScheduler Committer 的完整指南从贡献者到 PMC 成员的晋升之路下一篇Obsidian Templater插件完整指南打造智能笔记自动化系统创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表