马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
文章中出现的代码是演示版本,仅供参考,实际的业务需求会更加复杂
什么是动态路由
什么场景会用到动态路由
举一个最常见的例子,比如说我们要开发一个背景管理体系,一样平常来说背景管理体系都会分脚色登录,这个时间也就涉及到了权限,比如说这个背景管理体系如今有超等管理员,管理员,运维,财政等这几个脚色,每个脚色登录体系之后都会有差别的权限,超等管理员必要全部的权限,财政大概只必要财政干系的模块(菜单)以及按钮等,通常实现这种需求会有以下常见方案
路由表由前端去维护
也就是说我们已知这几个脚色分别对应哪些权限,前端写好路由设置表,,后端只必要告诉你当前登录人是属于哪个脚色,前端根据脚色范例去写一个过滤函数,获取该脚色所拥有的菜单以及按钮,然后动态的去添加路由,如许做有一个缺点就是,如果又增长了一个新的脚色怎么办?某个脚色想增长一些权限怎么办?这个时间前端就必要去新增大概修改代码,一点也不友爱
路由表的数据由后端返回
这种也是常用的一种方式,大概我们的体系内里必要开发一些功能,如菜单管理,脚色管理,用户管理等,也就是常说的权限中央,前端开发完的页面所对应的路由信息有后端去维护,这个时间我们在开发的时间必要束缚某一种规则,比如全部页面都放到/src/views目的下面,然后通过菜单管理去维护数据,维护完的数据可以到脚色管理内里去设置脚色菜单,设置完脚色,可以到用户管理内里给某个用户设置脚色等一些列流程,如许的话纵然新增一个脚色,大概修改一个脚色的脚色菜单,前端都不必要去修改代码,只要在菜单管理内里维护好了数据,想怎么改怎么改,后端返回的数据格式大概如下:
- [
- {
- path: "/application",
- name: "application",
- component: "Layout",
- title: "应用管理",
- show: true,
- icon: "",
- children: [
- {
- path: "",
- name: "application-index",
- component: "/application/index.vue",
- },
- ],
- },
- {
- path: "/permission",
- name: "permission",
- component: "Layout",
- title: "权限管理",
- show: true,
- icon: "",
- children: [
- {
- path: "menu",
- name: "permission-menu",
- component: "/permission/menu/index.vue",
- title: "菜单管理",
- show: true,
- icon: "",
- },
- {
- path: "user",
- name: "permission-user",
- component: "/permission/user/index.vue",
- title: "用户管理",
- show: true,
- icon: "",
- },
- {
- path: "role",
- name: "permission-role",
- component: "/permission/role/index.vue",
- title: "角色管理",
- show: true,
- icon: "",
- },
- ],
- },
- ]
复制代码 着实细致观察这个数据结构,是不是有点熟悉,path,name,component,children,我们似乎手动维护路由表的时间也会用到这些属性
怎样实现动态路由
实现动态路由着实就要用到vue-router提供的一个方法,叫addRoute在之前版本的时间是addRoutes,如今非版本的vue-router给废除了
addRoute()怎样利用呢?可以看一下官方文档
当我们添加一个主路由的时间
- router.addRoute({ path: '/permission', name: 'permission', component: () => import('xxxxx')})
复制代码 添加子路由也就是嵌套路由
- router.addRoute('主路由的name', { path: 'settings', component: AdminSettings })
复制代码
既然我们已经知道了addRoute()方法怎样利用,下面我们就可以去实现这部门逻辑
我们看一下官方文档的导航保卫内里的内容
在之前我们利用导航保卫的时间必要一个参数next()去控制是否放行以及去哪个页面,但是在新版本的vue-router内里可以不是用next(),固然你是用也行~
我们可以新建一个permission.ts文件
- import router from "./index";
- import { useSessionStorage } from "@vueuse/core";
- import { StorageEnum } from "@/enum";
- import { useUserStore } from "@/store";
- const whiteList = ["/login", "/404"];
- router.beforeEach(async (to) => {
- const token = useSessionStorage(StorageEnum.TOKEN, "").value;
- // 如果在白名单里面 并且 token 不存在
- if (whiteList.includes(to.path) && !token) {
- return true;
- } else {
- const { menuList, getMenuList } = useUserStore();
- // 如果为空数组,name就请求接口重新获取后端维护的路由数据
- if (!menuList.length) {
- await getMenuList();
- console.log("获取全部路由 =>", router.getRoutes());
- // 触发重定向 不这样写会导致刷新找不到路由 两种写法都行
- // return { path: to.fullPath };
- return to.fullPath;
- }
- }
- });
复制代码 这里我们可以看到一会return true一会return to.fullpath是为什么,通过官方导航保卫内里的先容,我们可以知道的是
通过官方文档动态路由,我们可以直到
以是说return to.fullpath是官方告诉我们要这么利用,也是为相识决动态路由页面革新的时间会出现页面空缺大概404的标题
出现404的话比如说你在路由表中维护了下面路由映射
- {
- path: "/:pathMatch(.*)",
- name: "page404",
- component: () => import("@/views/system/404.vue"),
- }
复制代码 上面说的紧张是在全局导航保卫内里的一些利用及留意事项,我们可以看到并没有用到addRoute()这个方法,也没有出现拿到后端数据前端转换成路由表的干系代码,但是我们可以看到有一个getMenuList()函数,我们在开发的时间,肯定是要思量到复用以及复杂逻辑抽取的标题,一个动态路由的实现会扳连到很多知识点接口哀求,vuex大概pinia状态维护,vue-router,vite内里怎么获取文件等
下面看一下怎样获取到接口给的数据,转换成vue-router可以大概辨认的数据
起首我们要看一个vite官方给提供的功能,我们拿到后端给的文件路径如上面代码出现的component字段,如/application/index.vue,这个文件大概在我们当地项目中的src/views/application/index.vue这个路径下

我们必要把它转换成一个下面的格式() => import('xxxx'),我们必要动态的去拼接获取文件,该怎么实现呢?
vite官方文档中有分析

必要利用import.meta.glob,这个时间我们可以打印一下import.meta.glob("../views/**"),看一下返回的到底是什么

返回的是一个对象,而对象的key我们可以拼接获取到,而value正是我们想要的动态获取的文件路径
以下代码仅供参考,有很多必要美满的地方,只为演示利用
- import type { RouterType } from "@/router/type";
- import router from "@/router";
- import type { RouteRecordRaw } from "vue-router";
- export const useRouterConfig = () => {
- // 获取views目录下的所有的文件 不要使用@别名
- const modules = import.meta.glob("../views/**");
- const asyncRoutes = ref<RouterType[]>([]);
- const addRoutes = (menus: RouterType[]) => {
- asyncRoutes.value = menus;
- filterAsyncRouter();
- // 动态添加 / 路由
- router.addRoute({
- path: "/",
- redirect: asyncRoutes.value[0].path,
- });
- };
- const filterAsyncRouter = () => {
- const routerLoop = (routes: RouterType[], ParentName?: string) => {
- routes.forEach((item) => {
- if (item.component === "Layout") {
- item.component = () => import("@/layout/index.vue");
- } else {
- item.component = resolveComponent(item.component);
- }
- const { title, show, icon, name, path, component, children } = item;
- const route: RouteRecordRaw = {
- component,
- path,
- name,
- meta: {
- title,
- show,
- icon,
- },
- children: children as any,
- };
-
- // 动态添加路由
- if (ParentName) {
- router.addRoute(ParentName, route);
- } else {
- router.addRoute(route);
- }
- if (item.children && item.children.length > 0) {
- routerLoop(item.children, item.name);
- }
- });
- };
- routerLoop(asyncRoutes.value);
- };
- const resolveComponent = (path: string) => {
- console.log(modules);
- // 拿到views下面的所有文件之后,动态拼接`key`去获取value
- const importPage = modules[`../views${path}`];
- if (!importPage) {
- throw new Error(
- `Unknown page ${path}. Is it located under Pages with a .vue extension?`
- );
- }
- return importPage;
- };
- return { addRoutes };
- };
复制代码 综上所述:
要想实现vite+vue-router实现动态路由我们必要用到
- addRoute()
- import.meta.glob()
- 获取后端tree数据,递归循环,大概业务会有type范例,比如分为模块,菜单,页面,按钮等,到时间团结业务去实现逻辑
- 导航保卫利用时的留意事项,否则会出现革新白屏,大概路由访问死循环等
|