直接上代码
import router from '@/router';
import { useUserStore } from '@/store';
// 导入需要匹配的文件夹
const constantRouterComponents = importa.glob('./views/**/*.vue', {
eager: true,
});
// 导入需要匹配的文件夹
const layoutRouterComponents = importa.glob('./layout/**/*.vue', {
eager: true,
});
打印看看constantRouterComponents数据格式,大概张这样 -> -> ->
/**
* {
* './views/dashboard/monitor/components/chat-item.vue': {},
* './views/dashboard/monitor/components/data-statistic-list.vue': {}
* }
*/
// 这里假设是后端返回的路由文件
const adminRoutes = [
{
path: '/dashboard',
name: 'dashboard',
component: 'layout/default-layout', // 父级菜单 可做常量选择, layout/default-layout | layout/page-layout
meta: {
locale: 'menu.dashboard',
requiresAuth: true,
icon: 'icon-dashboard',
},
children: [
{
path: 'workplace',
name: 'Workplace',
/// component 字段录入时按照 importa.glob('./views/**/*.vue', { eager: true, }); 导入文件名即views 继续录入
/// 例如文件地址views/dashboard/workplace/index.vue 可录入dashboard/workplace 或者 dashboard/workplace/index.vue 前面不带斜杠/
/// TODO 规则也可按照自己要求重新定义
component: 'dashboard/workplace',
meta: {
locale: 'menu.dashboard.workplace',
requiresAuth: true,
},
},
],
},
{
path: '/list',
name: 'list',
component: 'layout/default-layout',
meta: {
locale: 'menu.list',
requiresAuth: true,
icon: 'icon-list',
},
children: [
{
path: 'card',
name: 'Card',
component: 'list/card',
meta: {
locale: 'menu.list.cardList',
requiresAuth: true,
},
},
],
},
];
const complementComponent = (componentKey) => {
/**
* 说下思路
* componentKey是唯一标识,录入时可以录入文件路径。可以根据componentKey匹配到对应的vue文件即可。
*/
/// layout component
if (componentKey === 'layout/default-layout') {
return (layoutRouterComponents[`./${componentKey}.vue`] || {}).default;
}
/*
* 补全示例
* componentKey='user/card.vue' =》 ./views/user/card.vue
* componentKey='user/card' =》 ./views/user/card/index.vue
* 最终结果在 constantRouterComponents 能匹配到就ok
*/
let key = '';
const hasExtVue = componentKey.indexOf('.vue');
if (hasExtVue >= 0) {
key = `./views/${componentKey}`;
} else {
key = `./views/${componentKey}/index.vue`;
}
// 不支持动态import 所以找不到匹配文件无法兜底了。
return (constantRouterComponents[key] || {}).default;
};
const generator = (routerMap) => {
return routerMap.map((item) => {
const { title, show, hideChildren, hiddenHeaderContent, target, icon } = item.meta || {};
const currentRouter = {
path: item.path,
// 路由名称,建议唯一
name: item.name || '',
component: complementComponent(item.component),
meta: {
title,
icon: icon || undefined,
hiddenHeaderContent,
target,
},
};
// 是否设置了隐藏菜单
if (show === false) {
currentRouter.hidden = true;
}
// 是否设置了隐藏子菜单
if (hideChildren) {
currentRouter.hideChildrenInMenu = true;
}
// 为了防止出现后端返回结果不规范,处理有可能出现拼接出两个 反斜杠
if (!currentRouter.path.startsWith('http')) {
currentRouter.path = currentRouter.path.replace('//', '/');
}
// 重定向
// eslint-disable-next-line no-unused-expressions
item.redirect && (currentRouter.redirect = item.redirect);
// 是否有子菜单,并递归处理
if (item.children && item.children.length > 0) {
// Recursion
currentRouter.children = generator(item.children);
}
return currentRouter;
});
};
router.beforeEach((to, from, next) => {
const userInfo = useUserStore();
// 用户是否添加过路由 bool
if (!userInfo.syncRoutes) {
const resultRoutes = generator(adminRoutes);
(resultRoutes || []).forEach((element) => {
router.addRoute(element);
});
userInfo.syncRoutes = true;
next({ ...to, replace: true });
} else {
next();
}
});
复制代码
|