路由權限的設計思路:
首先,我們的需要校驗權限的路由的 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>