vue3 动态路由

50 阅读2分钟

route.js

import { routes, asyncRoutes } from '@/router';
import { permissionList } from '@/api/login';
const usePremissionStore = defineStore('Premission', {
	state: () => ({
		addRouters: [],
	}),
	actions: {

		SET_ADD_ROUTERS(data) {
			this.addRouters = data;
		},
		async GET_PERMISSION() {
			const { result: list } = await permissionList();
			let commonRouter = buildAccessibleRoutes(list, asyncRoutes);
			this.SET_ADD_ROUTERS(commonRouter);

		},
	},
});

export default usePremissionStore;

/**
 * ⚠️ 新的实现方案,支持无限层级路由
 * 以后端返回的路由树为准,构建权限路由表
 * @param {Array} backendRoutes - 后端返回的完整路由树
 * @param {Array} frontendRoutes - 前端定义的所有异步路由配置
 * @returns {Array} 过滤和排序后的最终路由表
 */
function buildAccessibleRoutes(backendRoutes, frontendRoutes) {
	// 1. 为了方便快速查找,将前端路由拍平并存入 Map
	//    键是路由的 path,值是完整的路由对象
	const frontendRouteMap = new Map();
	frontendRoutes.forEach((route) => {
		// 使用递归函数来拍平任意层级的路由
		const flattenRoutes = (r) => {
			if (r.children && r.children.length > 0) {
				frontendRouteMap.set(r.path.split('/')[1], r);
				r.children.forEach((child) => flattenRoutes(child));
			} else {
				frontendRouteMap.set(r.path, r);
			}
		};
		flattenRoutes(route);
	});
	// 2. 核心:递归函数,根据后端路由树构建新的路由表
	const buildTree = (backendTree) => {
		const accessibleRoutes = [];
		for (const backendRoute of backendTree) {
			// 从 Map 中查找对应的组件配置
			const frontendRouteConfig = frontendRouteMap.get(backendRoute.path); // 假设后端路由的path字段与前端一致
			// 如果前端存在该路由的配置
			if (frontendRouteConfig) {
				// 创建一个新的路由对象,避免直接修改原始的 asyncRoutes
				const newRoute = {
					...frontendRouteConfig, // 复制前端配置 (component, meta, etc.)
					children: [], // 准备接收子路由
				};
				// 处理 xxx 的特殊逻辑
				if (backendRoute.api) {
					if (import.meta.env.VITE_APP_ENV === 'development') {
						newRoute.meta.thirdLink = import.meta.env.VITE_APP_BASE_URL + '/' + backendRoute.api;
					} else {
						newRoute.meta.thirdLink = location.origin + '/' + backendRoute.api;
					}
				}
				// 如果后端路由有子节点,则递归构建子路由
				if (backendRoute.children && backendRoute.children.length > 0) {
					newRoute.children = buildTree(backendRoute.children);
				}
				accessibleRoutes.push(newRoute);
			} else {
				// 如果在前端找不到对应配置,可以选择在这里打印一个警告,方便排查问题
				console.warn(`后端返回了路由 "${backendRoute.path}",但在前端 asyncRoutes 中未找到对应配置。`);
			}
		}
		return accessibleRoutes;
	};

	return buildTree(backendRoutes);
}

可以在全局路由守卫中调用

// 添加有权限的菜单
premissionStore.addRouters.forEach((ele) => {
    router.addRoute(ele);
});

flattenRoutes函数中要注意一级菜单的"/"处理,要保证能匹配上,我们后台权限树中一级菜单没有"/"所以这里做了特殊处理