路由
项目路由配置存放于 src/router/routes 下面。 src/router/routes/modules用于存放路由模块,在该目录下的文件会自动注册。
配置
模块说明
在 src/router/routes/modules 内的 .js 文件会被视为一个路由模块。
一个路由模块包含以下结构
import { t } from '@/hooks/gui/useI18n';
export default { path: '/capitalList', redirect: '/capitalList/capital', component: () => import('@/views/layout/default/index.vue'), meta: { title: t('routes.capitalList.capitalList'), role: 'apms:capital', icon: 'capital', sort: 1, }, children: [ { path: 'capital', name: 'capital', component: () => import('@/views/capitalList/capital/index.vue'), meta: { title: t('routes.capitalList.program'), role: 'apms:capital:program', }, }, ],};多级路由
示例
import { t } from '/@/hooks/web/useI18n';export default { path: '/overview', redirect: '/overview/statistics', component: () => import('@/views/layout/default/index.vue'), meta: { title: '数据概览', role: 'apms:overview', icon: 'icon-backlog', sort: 1, }, children: [ { path: '/statistics', name: 'statistics', component: () => import('@/views/overview/statistics/index.vue'), meta: { title: '数据统计', role: 'apms:overview:statistics', }, children: [ { path: 'statistics2', name: 'statistics2', component: () => import('@/views/overview/statistics/index.vue'), meta: { title: '数据统计', role: 'apms:overview:statistics', }, }, ], }, ],};Meta 配置说明
export interface RouteMeta { //菜单排序 sort?: number; // 路由title 一般必填 title: string; // 动态路由可打开Tab页数 dynamicLevel?: number; // 动态路由的实际Path, 即去除路由的动态部分; realPath?: string;
// 是否忽略权限,只在权限模式为Role的时候有效 ignoreAuth?: boolean; // 权限字符 role?: string; // Whether not to cache noCache?: boolean; // 是否固定标签 affix?: boolean; // 图标,也是菜单图标 icon?: string; // 内嵌iframe的地址 frameSrc?: string; // 指定该路由切换的动画名 transitionName?: string;
// 隐藏该路由在面包屑上面的显示 hideBreadcrumb?: boolean; // 隐藏所有子菜单 hideChildrenInMenu?: boolean; // 当前激活的菜单。用于配置详情页时左侧激活的菜单路径 currentActiveMenu?: string; // 当前路由不再标签页显示 hideTab?: boolean; // 当前路由不再菜单显示 hideMenu?: boolean; isLink?: boolean;}外部页面嵌套
只需要将 frameSrc 设置为需要跳转的地址即可
const IFrame = () => import('/@/views/sys/iframe/FrameBlank.vue');{ path: 'doc', name: 'Doc', component: IFrame, meta: { frameSrc: 'https://vvbin.cn/doc-next/', title: t('routes.demo.iframe.doc'), },},外链
只需要将 path 设置为需要跳转的HTTP 地址即可
{ path: 'https://vvbin.cn/doc-next/', name: 'DocExternal', component: IFrame, meta: { title: t('routes.demo.iframe.docExternal'), },}动态路由 Tab 自动关闭功能
若需要开启该功能,需要在动态路由的meta中设置如下两个参数:
dynamicLevel最大能打开的 Tab 标签页数realPath动态路由实际路径(考虑到动态路由有时候可能存在 N 层的情况, 例:/:id/:subId/:...), 为了减少计算开销, 使用配置方式事先规定好路由的实际路径(注意: 该参数若不设置,将无法使用该功能)
{ path: 'detail/:id', name: 'TabDetail', component: () => import('/@/views/demo/feat/tabs/TabDetail.vue'), meta: { currentActiveMenu: '/feat/tabs', title: t('routes.demo.feat.tabDetail'), hideMenu: true, dynamicLevel: 3, realPath: '/feat/tabs/detail', },}图标
这里的 icon 配置,会同步到 菜单(icon 的值可以查看此处)。
新增路由
如何新增一个路由模块
- 在 src/router/routes/modules 内新增一个模块文件。
示例,新增 test.js 文件
import { t } from '/@/hooks/web/useI18n';
export default { path: '/capitalList', redirect: '/capitalList/capital', component: () => import('@/views/layout/default/index.vue'), meta: { title: t('routes.capitalList.capital'), role: 'apms:capital', icon: 'capital', sort: 2, }, children: [ { path: 'capital', name: 'capital', component: () => import('@/views/capitalList/capital/index.vue'), meta: { title: t('routes.capitalList.program'), role: 'apms:capital:program', }, }, ],};此时路由已添加完成,不需要手动引入,放在src/router/routes/modules 内的文件会自动被加载。
验证
访问 ip:端口/about/index 出现对应组件内容即代表成功
路由刷新
项目中采用的是重定向方式
实现
import { useRedo } from '/@/hooks/web/usePage';import { defineComponent } from 'vue';export default defineComponent({ setup() { const redo = useRedo(); // 执行刷新 redo(); return {}; },});Redirect
import { ExceptionEnum } from '@/constants/exception.constant'
export const REDIRECT_NAME = 'Redirect'export const RedirectRoute = { path: '/redirect', name: 'RedirectTo', component: () => import('@/views/layout/default/index.vue'), meta: { title: REDIRECT_NAME, hideBreadcrumb: true, hideMenu: true, }, children: [ { path: '/redirect/:path(.*)', name: REDIRECT_NAME, component: () => import('@/views/redirect/index.vue'), meta: { title: REDIRECT_NAME, hideBreadcrumb: true, }, }, ],}多标签页
标签页使用的是 keep-alive 和 router-view 实现,实现切换 tab 后还能保存切换之前的状态。
如何开启页面缓存
开启缓存有 3 个条件
- 在 src/settings/project.setting.js 内将
openKeepAlive设置为true - 路由设置
name,且不能重复 - 路由对应的组件加上
name,与路由设置的name保持一致
{ ..., // name name: 'Login', // 对应组件组件的name component: () => import('/@/views/sys/login/index.vue'), ... },
// /@/views/sys/login/index.vue export default defineComponent({ // 需要和路由的name一致 name:"Login" });如何让某个页面不缓存
在 src/settings/projectSetting.js 内将openKeepAlive 设置为 true时,已打开标签页面暂不支持不缓存
如何更改首页路由
首页路由指的是应用程序中的默认路由,当不输入其他任何路由时,会自动重定向到该路由下,并且该路由在 Tab 上是固定的,即使设置affix: false也不允许关闭
例:首页路由配置的是/dashboard/analysis,那么当直接访问 http://localhost:3100/ 会自动跳转到http://localhost:3100/#/dashboard/analysis 上(用户已登录的情况下)
可以将router.setting.js中的BASE_HOME更改为需要你想设置的首页即可
import { convertRefToReadonly } from '@/utils'
export const pagePresets = convertRefToReadonly({ BASE_LOGIN: '/login', BASE_HOME: '/homeDemo', ERROR_PAGE: '/exception',})路由如何匹配可重复参数
如果你需要匹配具有多个部分的路由,如 /first/second/third,你应该用 *(0 个或多个)和 +(1 个或多个)将参数标记为可重复:
const routes = [ // /:chapters -> 匹配 /one, /one/two, /one/two/three, 等 { path: '/:chapters+' }, // /:chapters -> 匹配 /, /one, /one/two, /one/two/three, 等 { path: '/:chapters*' },]在 routes 的 basic.js 中调整最新的匹配规则
export const RedirectRoute = { path: '/redirect', name: 'RedirectTo', ... children: [ { path: '/redirect/:chapters*', name: REDIRECT_NAME, ... }, ],}这将为你提供一个参数数组,而不是一个字符串,并且在使用命名路由时也需要你传递一个数组:
// 给定 { path: '/:chapters*', name: 'chapters' },router.resolve({ name: 'chapters', params: { chapters: [] } }).href// 产生 /router.resolve({ name: 'chapters', params: { chapters: ['id', 'name'] } }).href// 产生 /a/b
// 给定 { path: '/:chapters+', name: 'chapters' },router.resolve({ name: 'chapters', params: { chapters: [] } }).href// 抛出错误,因为 `chapters` 为空