在后台管理系统中,前端的路由往往需要根据用户的权限动态生成。这篇文章将重点介绍如何在 Vue 3 中实现动态路由注册和手动导航,确保用户访问的页面与权限对应。
1. 动态路由的需求与原理
为什么需要动态路由?
- 权限控制:不同用户角色需要看到不同的菜单和页面。
- 后端驱动:后端返回菜单数据,前端动态渲染菜单和注册路由。
- 避免硬编码:路由不再写死在前端代码里,保证灵活性。
- 动态注册路由:根据后端返回的数据,通过router.addRoute动态添加到路由系统。
- 手动导航:添加新路由后,需要手动触发导航保证路由生效。
静态路由是所有用户共享的基本路由,如登录页、404页等。import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router';
import Layout from '@/layout/admin.vue';
const routes: Array<RouteRecordRaw> = [
{
path: '/',
component: Layout,
name: 'admin',
},
{
path: '/login',
name: 'login',
component: () => import('@/pages/login/index.vue'),
meta: { title: '登录页' },
},
{
path: '/:pathMatch(.*)*',
name: 'NotFound',
component: () => import('@/pages/404/index.vue'),
meta: { title: '404' },
},
];
const asyncRoutes: Array<RouteRecordRaw> = [
{
path: '/',
name: '/',
component: () => import('@/pages/index/index.vue'),
meta: { title: '首页' },
},
{
path: '/goods/list',
name: '/goods/list',
component: () => import('@/pages/goods/list.vue'),
meta: { title: '商品列表' },
},
{
path: '/category/list',
name: '/category/list',
component: () => import('@/pages/category/list.vue'),
meta: { title: '分类列表' },
},
];
该方法接收后端返回的菜单数组,并将匹配的动态路由添加到主路由admin下。import { router } from '@/router/index';
export const addRoutes = (routesArray: Array<MenusArray>) => {
let hasNewRoutes = false;
const addRoutesFromMenus = (menus: Array<MenusArray>) => {
menus.forEach((menu) => {
const route = asyncRoutes.find((r) => r.path === menu.frontpath);
// 添加到router中
if (route && !router.hasRoute(route.path)) {
router.addRoute('admin', route);
hasNewRoutes = true;
}
// 递归处理子菜单
if (menu.child && menu.child.length > 0) {
addRoutesFromMenus(menu.child);
}
});
};
addRoutesFromMenus(routesArray);
return hasNewRoutes;
};
- router.addRoute:VueRouter提供的API,可以动态添加路由。
- 避免重复添加:router.hasRoute检查路由是否已存在,防止重复注册。
- 递归处理:支持多级菜单,递归遍历child子菜单。
在router.beforeEach路由守卫中,调用addRoutes注册动态路由,并实现手动导航。import { getToken } from '@/utils/auth';
import store from '@/store';
import { addRoutes } from '@/router/index';
router.beforeEach(async (to, from, next) => {
const token = getToken();
let hasNewRoutes = false;
// 显示全局加载状态
showFullLoading();
// 未登录跳转到登录页
if (!token && to.name !== 'login' && to.name !== 'NotFound') {
return next('/login');
}
// 已登录访问登录页,重定向到主页
if (token && to.name === 'login') {
return next('/');
}
// 已登录状态下,动态添加路由
if (token) {
await store.dispatch('user/getUserInfo'); // 拉取用户信息
hasNewRoutes = addRoutes(store.getters['menu/getMenus']); // 添加动态路由
}
// 设置页面标题
if (to.meta.title) {
document.title = `${to.meta.title}-测试后台管理`;
} else {
document.title = '测试后台管理';
}
// 手动导航:如果添加了新路由,重新跳转当前页面
hasNewRoutes ? next(to.fullPath) : next();
});
- router.addRoute是动态操作,添加新路由后需要重新跳转一次,确保用户能正常访问新注册的页面。
- next(to.fullPath):手动跳转到当前页面。
- 动态注册路由:调用
addRoutes
将菜单数据匹配的路由添加到 admin
下。 - 手动导航:动态路由添加完成后,使用
next(to.fullPath)
手动触发页面跳转。
- 动态路由:后端驱动,通过
addRoutes
动态注册。 - 灵活性:动态路由使前端代码更灵活,后端控制权限更方便。
阅读原文:原文链接
该文章在 2024/12/30 16:01:11 编辑过