门户网站用户端需要分板块展示,板块内容由管理端配置,包括板块名称,访问路径,路由组件,展示顺序,是否展示。如下图所示:
用户访问门户网站时,展示菜单跳转通过板块配置,动态生成路由。
1.后端接口获取路由
@GetMapping(value = "/router")
public Result<?> getRouterList() {
LambdaQueryWrapper<Block> query = new LambdaQueryWrapper<>();
query.eq(Block::getIsShow, true).orderByAsc(Block::getSort);
List<Block> blockList = blockService.list(query);
List<Map<String, Object>> routeMapList = new ArrayList<>();
blockList.forEach(block -> {
Map<String, Object> map = new HashMap<>();
map.put("path", block.getPath());
map.put("component", block.getComponent());
map.put("name", block.getComponent());
routeMapList.add(map);
});
return Result.OK(routeMapList);
}
2.路由配置文件 router/index.ts
import {createRouter, createWebHashHistory} from 'vue-router'
const router = createRouter({
history: createWebHashHistory(), // hash模式:createWebHashHistory,history模式:createWebHistory
routes: [
{
path: '/404',
component: () => import('@/views/404.vue'),
hidden: true
},
]
})
export default router
3.路由守卫 router/guard/index.ts
import {Router} from 'vue-router'
import {getRouterList} from "@/api/block";
import mainStore from "../../store";
let dynamicRouters = []
export async function dynamicRouter(router: Router) {
const {data: res} = await getRouterList()
dynamicRouters = res.result
const routeList = transformObjToRoute(dynamicRouters)
routeList.forEach((route: any) => {
//添加路由
router.addRoute(route);
});
}
/**
* views目录下找页面,设置component
* @param routeList
*/
function transformObjToRoute(routeList: any) {
let dynamicViewsModules: any = import.meta.glob('../../views/**/*.{vue,tsx}');
routeList.forEach((route: any) => {
const component = route.component as string;
if (component) {
route.component = dynamicImport(dynamicViewsModules, component)
}
});
return routeList;
}
function dynamicImport(dynamicViewsModules: any, component: string) {
const keys = Object.keys(dynamicViewsModules);
const matchKeys = keys.filter((key) => {
const k = key.replace('../../views', '');
const startFlag = component.startsWith('/');
const endFlag = component.endsWith('.vue') || component.endsWith('.tsx');
const startIndex = startFlag ? 0 : 1;
const lastIndex = endFlag ? k.length : k.lastIndexOf('.');
return k.substring(startIndex, lastIndex) === component;
});
if (matchKeys?.length === 1) {
const matchKey = matchKeys[0];
return dynamicViewsModules[matchKey];
} else if (matchKeys?.length > 1) {
return;
}
}
/**
* 页面未找到
*/
export const PAGE_NOT_FOUND_ROUTE: any = {
path: '/:path(.*)*',
name: "NotFound",
component: () => import('@/views/404.vue')
};
/**
* 动态路由权限控制
* @param router
*/
export function setupPermissionGuard(router: Router) {
router.beforeEach(async (to, from, next) => {
//判断是否已经添加过动态路由,添加过,直接放行
if (mainStore.getters.getIsDynamicAddedRoute) {
next();
return;
}
//没有添加过,添加,添加后跳转页面
await dynamicRouter(router)
router.addRoute(PAGE_NOT_FOUND_ROUTE);
mainStore.commit('setDynamicAddedRoute', {
isDynamicAddedRoute: true
})
next({...to, replace: true})
});
}
4.main.ts配置路由守卫
import App from './App.vue'
import router from '@/router'
import {setupPermissionGuard} from '@/router/guard'
async function bootstrap() {
// 创建应用实例
const app = createApp(App);
app.use(router) // 引用路由实例
setupPermissionGuard(router);
await router.isReady();
// 挂载应用
app.mount('#app', true);
}
bootstrap()