路由权限的设计思路:
首先,我们的需要校验权限的路由的 url
,全部由后端返回,后端会返回当前用户的路由树数组。
前端在进入页面前请求接口,把数据拿到:
其次,前端会维护一个路由映射组件的列表,如果路由中拿到 url, 匹配到了对应的组件,那么将该组件添加到路由对象中去,相当于,前端路由都是动态生成的。
前端拿到这个路由树数组后,进行递归遍历,将路由树里的一级菜单、二级菜单,寻找对应的组件。
// main.js const vm = new Vue({ router, store, i18n, render: h => h(App), beforeCreate() { getMenu(); // 进入系统前,请求接口 } }).$mount("#app"); // 请求后台接口函数,拿到菜单数据和按钮权限数组, export const getMenu = async () => { const req: any = {}; return new Promise(resolve => { Http.get(Url.base.getMenu, req).then((response: AxiosResponse) => { let result = response.data; if (result.code === Code.SUCCESS) { let resultMap = {}; let menu = result.data.menuInfoMapList; // 拿到菜单 url 的 list map let permission = result.data.operateMapList; // 拿到按钮权限数据的数组 let formatedRoutes = formatRoutes(menu); // 递归菜单,格式化后的菜单树, let formatedPermission = formatPermission(permission); // 权限数组 resultMap = { formatedRoutes, formatedPermission }; router.addRoutes(formatedRoutes); // 利用 vue-router 的 addRoutes 方法,将格式化后的代码添加到路由对象中 store.commit("base/saveMenu", formatedRoutes); // 将格式化的菜单树放入状态管理中保存。 store.commit("setPermission", formatedPermission); // 将格式化的权限数组也放入状态管理中保存 resolve(resultMap); } else { resolve([]); } }); }); }; /** * 格式化菜单数据为 vue-router 路由对象格式 */ export const formatRoutes = (menu: any) => { if (!menu) { return []; } let result = menu.map((item: any) => { let children = []; if (item.child) { children = formatRoutes(item.child); // 递归遍历权限树 } return { path: item.url || "/layout", // 如果没有 url, 做一个容错处理,避免路由没有 path component: lazyload(item.url), // loayload 是一个方法,传入 url 作为键,返回 url 对应的组件引用。 meta: { title: item.name }, children: children }; }); return result; }; 前端拿到的数据大致为: data: { menuInfoMapList: [ { url: "/fruits", name: "水果", child: [ { url: "/fruits/apple", // 二级菜单 name: "苹果" } , { url: "/fruits/banana", // 二级菜单 name: "香蕉" } ] } ], operateMapList: [ "/eatApple", // 按钮权限 code "/eatBanana" // 按钮权限 code ] } // 下面就是 loazload.ts 文件,维护了后台传来的 url, 和页面编写好的 组件位置。导出一个函数,就是上面的 loazload 函数。 const routes: any = { // ===== 权限管理 ===== "/friuts": () => import("@/layout/Layout.vue"), // 一级菜单的 url 和组件 "/friuts/apple": () => import("@/views/Apple.vue"), // 二级菜单的 url 和组件 "/friuts/banana": () => import("@/views/Banana.vue"), // 二级菜单的 url 和组件 }; export default (path: any) => routes[path]; // 下面是按钮权限的控制,比较简单,就是把按钮的 code) 传入校验函数,校验函数就是判断 按钮的 url 在没有在 后台返回的 url 列表中。 export function authHelper(authCode: string) { let isExist = store.getters["getPermissionList"].includes(authCode); return isExist; } // 页面组件上,通过 权限 code 控制按钮权限 <Button v-if="$authHelper("/eatApple")" @click="handleEat">苹果</Button>