Vue 项目中基于后端权限的动态路由实现

首先页面需要准备三个数组:基础路由,完整路由,模拟接口数据

  1. 基础路由也就是静态路由(只有基本页面配置,不包含动态路由的组件。也是接下来用于注册页面的数组)

    // 基础路由(只有基本页面配置,不包含动态路由的组件)
    const baseRoutesWithoutComponents = [
    {
    path: '/',
    name: 'login',
    component: () => import("@/views/Login.vue")
    },
    {
    path: '/404',
    name: '404',
    component: () => import('@/views/notFound.vue')
    },
    {
    path: '/layout',
    name: 'layout',
    component: () => import('@/components/all.vue'),
    children: [] // 初始为空,动态路由将添加到这里
    }
    ];

2.完整路由配置(包含所有可能的页面组件。不能注册这个)

复制代码
// 完整路由配置(包含所有可能的页面组件)
const baseRoutesWithComponents = [
    {
        path: '/',
        name: 'login',
        component: () => import("@/views/Login.vue")
    },
    {
        path: '/404',
        name: '404',
        component: () => import('@/views/notFound.vue')
    },
    {
        path: '/layout',
        name: 'layout',
        component: () => import('@/components/all.vue'),
        children: [
            {
                path: '/home',
                name: '首页',
                id: 1,
                pid: 0,
                component: () => import('@/views/homeView.vue')
            },
            {
                id: 2,
                pid: 0,
                redirect: null,
                path: '/comp',
                name: '门诊',
                component: () => import('@/views/outpatientView.vue'), // 添加父级组件
                children: [
                    {
                        id: 3,
                        pid: 2,
                        redirect: null,
                        component: () => import('@/views/payView.vue'),
                        path: "/pay",
                        name: "门诊缴费记录",
                        children: [
                            {
                                id: 13,
                                pid: 3,
                                redirect: null,
                                component: () => import('@/views/payDetailView.vue'),
                                path: "/pay/detail",
                                name: "具体缴费明细"
                            }
                        ]
                    },
                    {
                        id: 4,
                        pid: 2,
                        redirect: null,
                        component: () => import('@/views/reservationView.vue'),
                        path: "/reservation",
                        name: "预约记录"
                    }
                ]
            },
            {
                id: 8,
                pid: 0,
                path: '/hospital',
                name: '住院',
                component: () => import('@/views/hospitalParentView.vue'), // 添加父级组件
                children: [
                    {
                        id: 9,
                        pid: 8,
                        redirect: null,
                        component: () => import('@/views/hospitalView.vue'),
                        path: "/hospitalpay",
                        name: "住院缴费记录"
                    },
                    {
                        id: 10,
                        pid: 8,
                        redirect: null,
                        component: () => import('@/views/roomView.vue'),
                        path: "/room",
                        name: "房间管理"
                    },
                    {
                        id: 11,
                        pid: 8,
                        redirect: null,
                        component: () => import('@/views/inpatientView.vue'),
                        path: "/inpatient",
                        name: "住院人"
                    }
                ]
            }
        ]
    }
];

3.这个数组是模拟接口返回的数据(不包含component)

复制代码
// 动态路由配置(权限过滤后的结构)
const dynamicRouteConfigs = [
    {
        path: '/home',
        name: '首页',
        id: 1,
        pid: 0
    },

    {
        id: 2,
        pid: 0,
        redirect: null,
        path: '/comp',
        name: '门诊',
        children: [
            {
                id: 3,
                pid: 2,
                redirect: null,
                path: "/pay",
                name: "门诊缴费记录",
                children: [
                    {
                        id: 13,
                        pid: 3,
                        redirect: null,
                        path: "/pay/detail",
                        name: "具体缴费明细"
                    }
                ]
            },
            {
                id: 4,
                pid: 2,
                redirect: null,
                path: "/reservation",
                name: "预约记录"
            }
        ]
    },
    {
        id: 8,
        pid: 0,
        path: '/hospital',
        name: '住院',
        children: [
            {
                id: 9,
                pid: 8,
                redirect: null,
                path: "/hospitalpay",
                name: "住院缴费记录"
            },
            {
                id: 10,
                pid: 8,
                redirect: null,
                path: "/room",
                name: "房间管理"
            },
            {
                id: 11,
                pid: 8,
                redirect: null,
                path: "/inpatient",
                name: "住院人"
            }
        ]
    }, {
        path: '/message',
        name: '住院人信息',
        id: 12,
        pid: 0
    },
];

注册静态路由

复制代码
// 创建路由实例,只注册静态路由
const router = createRouter({
    history: createWebHistory(),
    routes: baseRoutesWithoutComponents
});

数据处理

复制代码
// 改进的权限过滤方法,支持多维数组(嵌套路由)
const filterRoutes = (dynamicRouteConfigs, allRoutes) => {
    // 递归查找匹配的路由
    const findMatchedRoute = (routes, target) => {
        for (const route of routes) {
            // 匹配条件:name和path都相同
            if (route.name === target.name && route.path === target.path) {
                return route;
            }
            // 如果有子路由,递归查找
            if (route.children) {
                const matchedChild = findMatchedRoute(route.children, target);
                if (matchedChild) return matchedChild;
            }
        }
        return null;
    };

    // 递归处理路由配置
    const processRoutes = (routes) => {
        return routes.map(route => {
            // 查找匹配的路由配置
            const matchedRoute = findMatchedRoute(allRoutes, route);

            if (!matchedRoute) return null;

            // 创建新的路由配置
            const newRoute = {
                ...route,
                component: matchedRoute.component,
                redirect: matchedRoute.redirect || null
            };

            // 递归处理子路由
            if (route.children && route.children.length > 0) {
                newRoute.children = processRoutes(route.children);
            }

            return newRoute;
        }).filter(route => route !== null);
    };

    return processRoutes(dynamicRouteConfigs);
};

将处理后的数据添加到静态路由

复制代码
// 动态添加路由到 layout
const addDynamicRoutes = (roles) => {
    // 清空已有动态路由
    const layout = router.getRoutes().find(r => r.name === 'layout');
    if (layout) {
        layout.children.forEach(child => {
            router.removeRoute(child.name);
        });
    }

    // 过滤并添加新路由
    const allowedRoutes = filterRoutes(dynamicRouteConfigs, baseRoutesWithComponents);
    allowedRoutes.forEach(route => {
        router.addRoute('layout', route);
    });

    // 存储路由信息
    sessionStorage.setItem('menuPath', JSON.stringify(allowedRoutes));
    sessionStorage.setItem('menuName', JSON.stringify(router.getRoutes()));

    // 确保 404 最后处理
    router.addRoute({
        path: '/:pathMatch(.*)*',
        redirect: '/404'
    });

    console.log('动态路由添加完成:', allowedRoutes);
};

// 示例调用(实际使用时应该根据用户权限调用)
addDynamicRoutes();
相关推荐
尾善爱看海6 小时前
Vue 面试收官篇:SSR、性能优化落地、30 道高频面试题精讲(附标准答案)
前端·javascript·vue.js·面试·vue
weixin_BYSJ19877 小时前
【计算机毕设】基于SpringBoot与Vue的文物保护档案管理系统08621
vue.js·spring boot·spring cloud·微服务·架构·django·课程设计
Bs_MoneyMagnet7 小时前
基于springboot+vue的个人健康管理系统的设计与实现 源码+文档
java·vue.js·spring boot·后端·vue3·springboot3·计算机毕业设计
驳是7 小时前
一个组件,提升 react-router 开发的幸福感
前端·preact
GreenTea7 小时前
OpenAI Agents API 上手实测:一次调用把整个 agent loop 甩给 OpenAI
前端·后端·算法
星云API技术支持7 小时前
企业微信二次开发:群权限设置、成员管理与群资料维护的接口组合实践
java·前端·企业微信
京东云开发者8 小时前
81.8 秒的视频,我们改了 15 个版本:一次纯 Codex 驱动的 AI-native 视频实践
前端·aigc
Csvn8 小时前
TypeScript 大型项目架构:从单体 tsconfig 到分层可扩展的工程
前端
Bs_MoneyMagnet10 小时前
基于springboot+vue的心理咨询预约与随访平台的设计与实现 源码+文档
vue.js·spring boot·后端·spring·毕业设计·旅游·计算机毕业设计
计算机魔术师10 小时前
Dario Amodei 发文呼吁为前沿 AI 降速并提出三点计划
前端