大家都知道,后台管理系统中,避不开的一个问题,就是角色权限,那么权限这块必然跟菜单路由关联。vue2中可以通过addRoutes函数,实现动态路由,那么vue3怎么实现呢
1.router.ts
vue3中使用addRoute方法可以实现,动态路由的加载
import { createRouter, createWebHashHistory, RouteRecordRaw } from "vue-router";
import { toTree } from "@/utils/tools";
import NProgress from "nprogress";
//NProgress:路由加载过渡动画
import { accountStore } from "@/store/index";
import { api_info } from "@/api/webPage";
import LocalStorage from "@/utils/localStorage";
const routes: Array<RouteRecordRaw> = [
{
path: "/",
name: "webPage", //展示页
component: () => import("@/views/webPage/index.vue"),
meta: { name: "主页" },
},
{
path: "/admin",
name: "admin",
meta: { name: "layout" },
component: () => import("@/views/layout/index.vue"),
children: [
{
path: "/home",
name: "首页", //展示页
component: () => import("@/views/home/index.vue"),
meta: { name: "主页" },
},
{
path: "/personalCenter",
name: "个人中心",
component: () => import("@/views/personalCenter/index.vue"),
meta: { name: "个人中心" },
},
],
},
{
path: "/:catchAll(.*)",
name: "404",
component: () => import("@/views/error/index.vue"),
},
];
const router = createRouter({
history: createWebHashHistory(),
routes,
});
/**导入路由对应菜单 */
function view(path: any) {
let modules = import.meta.glob("../views/**/*.vue");
return modules[`../views/${path}/index.vue`];
}
/**变成路由结构 */
function setRouters(params: any) {
let newRouter = params.map((r: any) => {
r.components = r.components.replace(/^\//g, "");
let route: any = {
path: r.path,
name: r.menuName,
component: view(r.components),
meta: {
type: r.type, // 1菜单 2目录 3 按钮
icon: r.icon, //图标
status: r.status, //是否显示
},
};
if (r.children) {
route.children = setRouters(r.children);
}
return route;
});
return newRouter;
}
let flag = false; //是否刷新过菜单
const whiteList = ["/"]; //白名单
/**路由守卫 */
router.beforeEach(async (to: any, from: any, next) => {
/**如果2次去的相同页面,不加载路由动画(针对于退出登录的) */
if (to.path !== from.path) {
NProgress.start();
}
const myAccountStore = accountStore();
let userId = myAccountStore.$state.userId;//获取userId
let token = LocalStorage.get("rmtk_token");//获取token
//如果去白名单,就放行
if (whiteList.indexOf(to.path) !== -1) {
next();
} else {
/**如果登录有userId和token,并且,没有加载过菜单。那就发起请求,获取用户菜单 */
if (!flag && userId && token) {
flag = true;
let res: any = await api_info({ userId }); //发起用户信息接口,获取token
if (res.code === 200) {
myAccountStore.setUserInfo(res.data);
} else if (res.code === 201) {
myAccountStore.setUserInfo(res.data);
}
/**变成树状 */
let userRouter = toTree(myAccountStore.$state.userRouter); //变成树状
/**变成路由结构 */
userRouter = setRouters(userRouter);
/**找到后台首页 */
router.options.routes.forEach((o: any) => {
if (o.name === "admin" || o.path === "/admin") {
userRouter.forEach((element: any) => {
/**添加路由到首页 */
router.addRoute("admin", element);
o.children.push(element);
});
}
});
next({ path: to.path });
} else {
//如果没有 userId || token就去登录
if (!userId || !token) {
next("/"); //本项目 '/'为登录页面
} else {
//如果有 userId || token放行
next(); //放行
}
}
}
});
router.afterEach(() => {
NProgress.done();//结束路由加载动画
});
export default router;
2.toTree.js(@/utils/tools)文件方法
export function toTree(arr: any) {
let map: any = {}; // 用于快速查找节点
let tree: any = []; // 最终的树形数组
// 先对原始数组进行遍历,为其添加一个指向其子节点的引用
for (let i = 0; i < arr.length; i++) {
let node = arr[i];
map[node.id] = {
...node,
children: [],
parentName: "",
hasChildren: null,
};
}
// 再遍历一次原始数组,为每个节点添加子节点
for (let i = 0; i < arr.length; i++) {
let node = arr[i];
if (node.parentId !== null) {
// 如果节点有父ID,则找到父节点,并将当前节点添加为其子节点
if (map[node.parentId]) {
map[node.parentId].children.push({
...map[node.id],
parentName: map[node.parentId].menuName,
});
} else {
tree.push(map[node.id]);
}
} else {
// 如果节点没有父ID,则直接添加到树形数组中
tree.push(map[node.id]);
}
}
/**设置有子级字段 */
function setHasChildren(tree: any) {
if (tree.length) {
tree.forEach((e: any) => {
if (e.children) {
setHasChildren(e.children);
}
e.hasChildren = e.children.length ? true : false;
});
}
}
setHasChildren(tree);
return tree;
}
3.补充:vue3退出登录,重置路由方法
/**退出登录 */
async function logOutHandler() {
await router.replace({ path: "/" });//此处可能为异步,所以用await,变成同步
await this.resetStore();//重置pinia
LocalStorage.clear();//清除缓存
location.reload();//刷新页面
}
以上是vue3实现动态路由的代码,欢迎大家补充。总结:vue3使用addRoute可以实现动态路由