效果图
- 在本示例管理系统中,由于每个用户的权限不一样,拥有的可以访问的路由页面也不一样。
- 用户能访问的路由页面都是后端根据权限动态配置的。
- 我们前端需要根据后端接口返回的路由表去动态增删路由,从而生成这个用户所拥有的路由。
permission.js
import store from "@/store";
import router from "./router";
import { getPermissionList, routerPackage } from "@/utils/permission";
import { Session } from "@/utils/cache";
// 获取菜单权限tree树
const loadAsyncRoutes = async () => {
const menuList = await getPermissionList();
let routesList = routerPackage(menuList);
routesList.forEach((route) => {
router.addRoute("HOME", route);
});
};
router.beforeEach(async (to, from, next) => {
// 开启进度条
store.commit("menu/set_Loading", true);
if (Session.get("token")) {
// 解决路由刷新出现空白
if (store.state.menu.menuList.length == 0) {
try {
await loadAsyncRoutes();
// 如果 addRoutes 并未完成,路由守卫会一层一层的执行执行,直到 addRoutes 完成,找到对应的路由
next({ ...to, replace: true });
} catch (error) {
next();
}
} else {
let curRoute = router.getRoutes().filter((item) => item.path == to.path);
if (curRoute.length && curRoute[0].components.default) {
document.title = to.name;
next();
} else {
next("/404");
}
}
} else {
if (to.path == "/login") {
next();
} else {
next("/login");
}
}
});
// 后置关闭进度条
router.afterEach(() => {
store.commit("menu/set_Loading", false);
});
utils/permission.js
//获取菜单权限tree树
export const getPermissionList = async () => {
let list = await getMenuTreeList();
if (list) {
store.commit("menu/set_MenuList", list);
}
// const menuList = packageMenuList(list); //开启过滤权限数组
return list;
};
// 路由组成一
export function routerPackage(menuList) {
const modules = import.meta.glob("../views/**/*.vue");
return menuList.filter((route) => {
if (route.component?.length) {
route.component = modules["../views" + route.component + ".vue"];
} else {
route.component = () => import("@/components/layout/RouteView.vue");
}
if (Array.isArray(route.children) && route.children.length) {
route.children = routerPackage(route.children);
}
return true;
});
}
// 路由组成二(使用改方法且修改 src/permission.js文件)
// export const routerPackage = (routerMap, parent) => {
// const modules = import.meta.glob("../views/**/*.vue");
// return routerMap.map((item) => {
// const currentRouter = {
// path: item.path,
// name: item.name,
// meta: {
// title: item.name,
// icon: item.icon || null,
// },
// };
// //验证父路由为空
// if (item.component?.length) {
// currentRouter.component = modules["../views" + item.component + ".vue"];
// } else {
// currentRouter.component = () =>
// import("@/components/layout/RouteView.vue");
// }
// // 是否有子菜单,并递归处理
// if (item.children?.length) {
// currentRouter.children = routerPackage(item.children, currentRouter);
// }
// return currentRouter;
// });
// };
面包屑BreadCrumb
<template>
<a-breadcrumb>
<a-breadcrumb-item v-for="(item, index) in listBread" :key="item.path">
<span v-if="index == 0">{{ item.name }}</span>
<router-link v-else :to="item.path">{{ item.name }}</router-link>
</a-breadcrumb-item>
</a-breadcrumb>
</template>
<script setup>
import { ref } from "@vue/reactivity";
import { watchEffect } from "@vue/runtime-core";
import { useRoute } from "vue-router";
const listBread = ref([]);
const route = useRoute();
// 监听路由变化
watchEffect(() => {
listBread.value = route.matched;
});
</script>
MultiTab文件(记录栈访问路由)暂不更新