Skip to main content

路由

打开 main.ts 文件看,和路由相关的注册事件有两个

  setupRouter(app);
setupRouterGuard(router);

路由列表是一个函数,第二个函数执行的是一些路由守卫的逻辑

基础路由

setupRouter 中,通过下面的代码可以知道核心的路由信息在 basicRoutes

export const router = createRouter({
// 创建一个 hash 历史记录。
history: createWebHashHistory(import.meta.env.VITE_PUBLIC_PATH),
// 应该添加到路由的初始路由列表。
routes: basicRoutes as unknown as RouteRecordRaw[],
// 是否应该禁止尾部斜杠。默认为假
strict: true,
scrollBehavior: () => ({ left: 0, top: 0 }),
});

basicRoutes 主要记录了一些静态的页面路由,比如登录、登录页面、结果页面等。这些页面不涉及权限,将其设置为基础的路由页面。

// src\router\routes\index.ts
export const basicRoutes = [
LoginRoute,
RootRoute,
...mainOutRoutes,
REDIRECT_ROUTE,
PAGE_NOT_FOUND_ROUTE,
];

这些页面没有权限逻辑,单纯是为了某些特殊情况下用来展示的页面,功能页面如登录,状态展示页面如 404,403 等页面

权限路由

上面路由是所有人都可以看到的,也是在初始化页面时候默认会显示的一些路由。 但是我们还需要一部分的路由和角色用户绑定,比如说管理员可以做看到一些管理页面,但是普通员工却看不到。

对于这类页面的权限绑定,我们会通过当前登录的用户信息,判断它下面有哪些权限路由,有的话添加到 routes 数组中,没有的话就过滤除去。

vue-vben-admin 的路由存放在  src/router/routes  下面。 src/router/routes/modules用于存放路由模块,在该目录下的文件会自动注册。

const modules = import.meta.glob("./modules/**/*.ts", { eager: true });

通过上面的代码,将 modules 下面所有以 ts 结尾的文件,都会收集到 modules 变量中。

import.meta.glob 可以将文件系统导入生成如下的数据

const modules = {
"./dir/foo.js": () => import("./dir/foo.js"),
"./dir/bar.js": () => import("./dir/bar.js"),
};

详情查看: https://cn.vitejs.dev/guide/features.html#glob-import

在进入到具体的 modules 文件夹下的内容来看,我们以 src\router\routes\modules\about.ts 为例

const about: AppRouteModule = {
path: "/about",
name: "About",
component: LAYOUT,
redirect: "/about/index",
meta: {
hideChildrenInMenu: true,
icon: "simple-icons:about-dot-me",
title: t("routes.dashboard.about"),
orderNo: 100000,
},
children: [
{
path: "index",
name: "AboutPage",
component: () => import("/@/views/sys/about/index.vue"),
meta: {
title: t("routes.dashboard.about"),
icon: "simple-icons:about-dot-me",
hideMenu: true,
},
},
],
};
export default about;

可以发现我们的每个 modules 下面的 ts 文件配置了我们路由的信息。

拿到 modules 后,再通过 Object.keys 进行循环处理,解析出我们的路由routeModuleList

Object.keys(modules).forEach((key) => {
const mod = (modules as Recordable)[key].default || {};
const modList = Array.isArray(mod) ? [...mod] : [mod];
routeModuleList.push(...modList);
});

通过上面的转换,最终我们可以获得如下的数据

[
{
"path": "/about",
"name": "About",
"redirect": "/about/index",
"meta": {
"hideChildrenInMenu": true,
"icon": "simple-icons:about-dot-me",
"title": "routes.dashboard.about",
"orderNo": 100000
},
"children": [
{
"path": "index",
"name": "AboutPage",
"meta": {
"title": "routes.dashboard.about",
"icon": "simple-icons:about-dot-me",
"hideMenu": true
}
}
]
},
...
]

将其赋值给我们的路由变量 asyncRoutes

还记得我们最开始执行的一个 setupRouterGuard(router); 函数么

在这个函数里面会执行 permissionStore.buildRoutesAction() 函数

它会通过各种权限模式,将我们的 asyncRoutes 做过滤

 switch (permissionMode) {
// 角色权限
case PermissionModeEnum.ROLE:
// 对非一级路由进行过滤
routes = filter(asyncRoutes, routeFilter);
// 对一级路由根据角色权限过滤
routes = routes.filter(routeFilter);
// Convert multi-level routing to level 2 routing
// 将多级路由转换为 2 级路由
routes = flatMultiLevelRoutes(routes);
break;
...
}

至此,最后 routes 剩下来的内容,就是我们当前用户可以看到的路由,也就是左侧菜单可以查看的