路由
项目路由配置存放于 src/router/routers 下面。 src/router/routers/modules用于存放路由模块,在该目录下的文件会自动注册。
模块说明
路由分为前端本地路由和后端返回路由,前端本地路由配置在 src/router/routers/modules 内的 .ts
文件会被视为一个路由模块。
项目登录后后端返回的路由和前端写死的路由会进行合并,最终组成整个路由结构。按照配置中的排序字段来进行排序。
RouteMeta 配置说明
export interface RouteMeta {
// 路由title 一般必填
title: string;
// 动态路由可打开Tab页数
dynamicLevel?: number;
// 动态路由的实际Path, 即去除路由的动态部分;
realPath?: string;
// 是否忽略权限,只在权限模式为Role的时候有效
ignoreAuth?: boolean;
// 可以访问的角色,只在权限模式为Role的时候有效
roles?: RoleEnum[];
// 是否忽略KeepAlive缓存
ignoreKeepAlive?: boolean;
// 是否固定标签
affix?: boolean;
// 图标,也是菜单图标
icon?: string;
// 内嵌iframe的地址
frameSrc?: string;
// 指定该路由切换的动画名
transitionName?: string;
// 隐藏该路由在面包屑上面的显示
hideBreadcrumb?: boolean;
// 如果该路由会携带参数,且需要在tab页上面显示。则需要设置为true
carryParam?: boolean;
// 隐藏所有子菜单
hideChildrenInMenu?: boolean;
// 当前激活的菜单。用于配置详情页时左侧激活的菜单路径
currentActiveMenu?: string;
// 当前路由不再标签页显示
hideTab?: boolean;
// 当前路由不再菜单显示
hideMenu?: boolean;
// 菜单排序,只对第一级有效
orderNo?: number;
// 忽略路由。用于在ROUTE_MAPPING以及BACK权限模式下,生成对应的菜单而忽略路由。2.5.3以上版本有效
ignoreRoute?: boolean;
// 是否在子级菜单的完整path中忽略本级path。2.5.3以上版本有效
hidePathForChildren?: boolean;
}
前端路由配置结构
一个前端本地路由模块包含以下结构:
import type { AppRouteRecordRaw } from "/@/router/Types";
import { LAYOUT } from "/@/router/Constant";
import { t } from "/@/hooks/web/UseI18n";
const flows: AppRouteRecordRaw = {
path: "/flow",
name: "FlowDemo",
component: LAYOUT,
redirect: "/flow/flowChart",
meta: {
menuSort: 18,
icon: "tabler:chart-dots",
title: t("routes.demo.flow.name")
},
children: [
{
path: "flowChart",
name: "flowChartDemo",
component: () => import("/@/views/demo/flow-chart/index.vue"),
meta: {
title: t("routes.demo.flow.flowChart")
}
}
]
};
export default flows;
多级路由
注意事项
- 整个项目所有路由
name
不能重复 - 所有的多级路由最终都会转成二级路由,所以不能内嵌子路由
- 除了 layout 对应的 path 前面需要加
/
,其余子路由都不要以/
开头
示例
import { AppRouteRecordRaw } from "/@/router/Types";
import { LAYOUT } from "/@/router/Constant";
const moreLevel: AppRouteRecordRaw = {
name: "多级目录",
path: "/test",
component: LAYOUT,
meta: {
title: "多级目录",
icon: "ion:folder-open-outline",
hideMenu: false,
menuSort: 10
},
children: [
{
name: "目录1",
path: "menu1",
meta: {
title: "目录1",
icon: "ion:folder-open-outline",
hideMenu: false,
menuSort: 1
},
children: [{
path: "/test/test1/test2",
name: "目录2",
meta: {
title: "目录2",
icon: "ion:folder-open-outline",
hideMenu: false,
menuSort: 1
},
children: [
{
path: "/test/test1/test2/test3",
name: "多级菜单",
meta: {
title: "多级菜单",
icon: "ant-design:appstore-outlined",
hideMenu: false,
menuSort: 1,
ignoreKeepAlive: false
},
component: () => import("/@/views/demo/flow-chart/index.vue")
}
]
}]
}
],
redirect: "/test/test1/test2/test3"
};
export default moreLevel;
外部页面嵌套
只需要将 frameSrc
设置为需要跳转的地址即可
const IFrame = () => import('/@/views/sys/iframe/FrameBlank.vue');
const Frame: AppRouteRecordRaw = {
path: "doc",
name: "Doc",
component: IFrame,
meta: {
frameSrc: "http://www.mfish.com.cn/",
title: t("routes.demo.iframe.doc")
}
}
外链
只需要将 path
设置为需要跳转的HTTP 地址即可
{
name: "1ce2ac44228e37c063e9cd55ed8f0a49",
path: "https://github.com/mfish-qf/mfish-nocode",
meta: {
title: "Git地址",
icon: "ion:logo-github",
hideMenu: false,
menuSort: 2,
ignoreKeepAlive: false,
frameSrc: "https://github.com/mfish-qf/mfish-nocode"
}
}
动态路由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',
},
}
新增前端本地路由
- 在 src/router/routes/modules 内新增一个模块文件。
示例,新增 flows.ts 文件
import type { AppRouteRecordRaw } from "/@/router/Types";
import { LAYOUT } from "/@/router/Constant";
import { t } from "/@/hooks/web/UseI18n";
const flows: AppRouteRecordRaw = {
path: "/flow",
name: "FlowDemo",
component: LAYOUT,
redirect: "/flow/flowChart",
meta: {
menuSort: 18,
icon: "tabler:chart-dots",
title: t("routes.demo.flow.name")
},
children: [
{
path: "flowChart",
name: "flowChartDemo",
component: () => import("/@/views/demo/flow-chart/index.vue"),
meta: {
title: t("routes.demo.flow.flowChart")
}
}
]
};
export default flows;
新增后端路由
多级菜单
外部页面嵌套
外链
带参菜单
此时路由已添加完成,不需要手动引入,放在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
src/views/sys/redirect/index.vue
import { defineComponent, unref } from 'vue';
import { useRouter } from 'vue-router';
export default defineComponent({
name: 'Redirect',
setup() {
const { currentRoute, replace } = useRouter();
const { params, query } = unref(currentRoute);
const { path } = params;
const _path = Array.isArray(path) ? path.join('/') : path;
replace({
path: '/' + _path,
query,
});
return {};
},
});
页面跳转
页面跳转建议采用项目提供的 useGo
方式
import { useGo } from '/@/hooks/web/usePage';
import { defineComponent } from 'vue';
export default defineComponent({
setup() {
const go = useGo();
// 执行刷新
go();
go(PageEnum.Home);
return {};
},
});
多标签页
标签页使用的是 keep-alive
和 router-view
实现,实现切换 tab 后还能保存切换之前的状态。
如何开启页面缓存
开启缓存有 3 个条件
- 在 src/settings/ProjectSetting.ts 内将
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"
});
注意
keep-alive 生效的前提是:需要将路由的 name
属性及对应的页面的 name
设置成一样。因为:
include - 字符串或正则表达式,只有名称匹配的组件会被缓存
如何让某个页面不缓存
可在 router.meta 下配置
可以将 ignoreKeepAlive
配置成 true
即可关闭缓存。
export interface RouteMeta {
// 是否忽略KeepAlive缓存
ignoreKeepAlive?: boolean;
}
如何更改首页路由
首页路由指的是应用程序中的默认路由,默认指向所有路由中排序第一的路由,并且该路由在Tab上是固定的,即使设置affix: false
也不允许关闭。
例:首页路由配置的是/dashboard/analysis
,那么当直接访问 http://localhost:5281/
会自动跳转到http://localhost:5281/#/dashboard/analysis
上(用户已登录的情况下)
修改方法
如果需要修改,请将首页配置排序放在最前面