灏天阁

vue3.2/Vite/Ts93: 菜单权限业务实现

· Yin灏

路由拆分

src/router/routes.ts

//...
// 常量路由
// 所有角色都包含的路由
export const constantRoute = [
  {
    //...
  },
  //...
];
// 异步路由
// 局部角色包含的路由
export const asyncRoute = [
  {
    //...
  },
  //...
];
// 任意路由
// 404
export const anyRoute = [
  {
    //...
  },
];

用户小仓库

src/store/modules/user.ts

//...
import { contantRoute, asyncRoute, anyRoute } from "@/router/routes";
import { userInfoResponseData } from "@/api/user/type";
//@ts-ignore
// 按需引入
import cloneDeep from "lodash/cloneDeep";
// 引入路由器对象
import router from "@/router";
//...
const filterAsyncRoute = (asyncRoute: any, routes: any) => {
  return asyncRoute.filter((item: any) => {
    if (routes.includes(item.name)) {
      if (item.children && item.children.length) {
        // 这里需要处理,不然会影响原数组(深拷贝问题)
        item.chidlren = filterAsyncRoute(item.children, routes);
      }
      return true;
    }
  });
};
//...
let useUserStore = defineStore("User", {
  state: (): UserState => {
    return {
      //...
      // 将路由对象挂载到用户小仓库
      menuRoutes: contantRoute,
    };
  },
  actions: {
    //...
    // 获取用户信息
    async userInfo() {
      const result: userInfoResponseData = await reqUserInfo();
      if (result.code === 200) {
        //...
        // 过滤路由
        let userAsyncRoute = filterAsyncRoute(
          cloneDeep(asyncRoute),
          result.data.routes
        );
        this.menuRoutes = [...contantRoute, ...userAsyncRoute, ...anyRoute];
        // 动态追加异步和任意路由
        [...userAsyncRoute, ...anyRoute].forEach((route: any) => {
          router.addRoute(route);
        });
        // 打印当前用户全部的路由
        console.log(router.getRoutes());
        return "ok";
      } else {
        return Promise.reject(new Error(result.message));
      }
    },
  },
});

解决异步路由刷新白屏问题

src/permisstion.ts

import nprogress from "nprogress";
import "nprogress/nprogress.css";
nprogress.configure({ showSpinner: false });
import router from "@/router";
import pinia from "./store";
import useUserStore from "./store/modules/user";
let userStore = useUserStore(pinia);
import setting from "./setting";
router.beforeEach(async (to: any, from: any, next: any) => {
  document.title = setting.title + "-" + to.meta.title;
  nprogress.start();
  let token = userStore.token;
  let username = userStore.username;
  if (token) {
    if (to.path === "/login") {
      next({
        path: "/",
      });
    } else {
      if (username) {
        next();
      } else {
        try {
          await userStore.userInfo();
          // 处理的这里
          // 用于在导航守卫中完成一些异步操作后,重新尝试导航
          next({ ...to });
        } catch (err) {
          userStore.userLogout();
          next({
            path: "/login",
            query: {
              redirect: to.path,
            },
          });
        }
      }
    }
  } else {
    if (to.path === "/login") {
      next();
    } else {
      next({
        path: "/login",
        query: {
          redirect: to.path,
        },
      });
    }
  }
});
router.afterEach((to: any, from: any) => {
  nprogress.done();
});

- Book Lists -