fengmoliu

导航

vue3动态路由添加

查看代码

import { createRouter, createWebHashHistory, RouteRecordRaw } from "vue-router";
import { App } from "vue";
import Cookies from "js-cookie";
import store from "../store";
import { getAdminInfo } from "../request/http";

const router = createRouter({
  history: createWebHashHistory(),
  routes: [
    {
      path: "/login",
      name: "login",
      component: () => import("../views/login/Login.vue"),
    },
  ],
});
// 封装动态路由
const genRoutesConfig = () => {
  // 添加动态路由
  // 1.获取vuex里面的getters数据
  // 2.循环getters数据
  // 不知道修改vuex里面的数据,先将数据放去一个变量里再修改
  let getNewMenus: NewMenusType = store.getters.getNewMenus;
  // 第一个for in循环用来循环一级菜单对象
  for (let key in getNewMenus) {
    // 创建一个变量去接收你想要路由的样子,接口 RouteRecordRaw 是routes内部自带的接口类型定义,用来约束路由的
    let newRouteObj: RouteRecordRaw = {
      // 按照以前配路由的方式书写路由,只是把静态数据变成动态数据 getNewMenus[key].name是每一个一级路由的名字
      path: "/" + getNewMenus[key].name,
      name: getNewMenus[key].name,
      // router-view是在homepage里面的组件,所有的组件都是在router-view展示,所以一级路由名字怎么变其实都是在homepage而已
      component: () => import("../views/homepage/Homepage.vue"),
      // children默认值是空数组,约束好类型,一会循环把二级标签循环进去
      children: [],
    };
    // 为什么这里循环前需要判断一下呢?主要是让js识别一定会有getNewMenus[key].children这个值,其实不写问题也不是很大,严谨一些而已,毕竟上面的children是个空数组,理论上是不可能是个undefined
    if (getNewMenus[key].children) {
      // 第二个for循环是根据每个一级路由的children的数量进行循环,这里children为什么使用!号,因为是想让ts肯定为有值的,并不是可能为undefined,ts约束规则比较繁琐,方便日后维护
      for (let i = 0; i < getNewMenus[key].children!.length; i++) {
        // 二级路由规则
        // 二级路由的规则跟一级路由差不多,不同的地方有两点:1.path前面不用添加"/",因为"/"代表的是从根目录出发,而二级路由的路径是通过一级路由拼接而成的,不需要从根目录开始出发
        let subRouteObj: RouteRecordRaw = {
          path: getNewMenus[key].children![i].name,
          name: getNewMenus[key].children![i].name,
          // 2.路径的拼接,二级路由的路径是由一级路径/二级路径名字拼接而成,所以我们不能写死一级路由名字跟二级路由名字
          component: () =>
            import(
              `../views/${getNewMenus[key].name}/${
                getNewMenus[key].children![i].name
              }.vue`
            ),
        };
        // subRouteObj 是接收循环路由配置的变量,每次配置完就将它放进 newRouteObj.children这个数组里面
        newRouteObj.children!.push(subRouteObj);
      }
    }
    // console.log(newRouteObj);
    // 动态添加路由
    // 每次循环完一级路由及一级路由的children数组的二级路由的时候,就往router添加路由,直至循环结束
    router.addRoute(newRouteObj);
  }
  // 这里为什么会写两个静态数据的路由添加上去呢,而不是直接在上面写呢?是因为当客户不是通过除登录页面进去的,一律不让其他人通过直接输入url路径访问后台,毕竟后台管理系统不是对所有人公开,只有通过正规的login页面登录成功进去才行,真正让人知道进入的页面其实只有一个login,其他都是动态生成的.
  router.addRoute({
    path: "/",
    name: "homepage",
    // 一级路由界面,动态生成不让通过输入url方式进入
    component: () => import("../views/homepage/Homepage.vue"),
    // "/"重定向"index",一进来首页的内容就放去index文件里面,它其实也是属于homepage的子路由,它的数据不在vuex里面,自己生成个就好
    redirect: "/index",
    children: [
      {
        path: "index",
        name: "index",
        component: () => import("../views/index/index.vue"),
      },
    ],
  });
};
// 前置路由守卫
// 前置路由守护有什么用?
// 1.可以让数据不会因为刷新而丢失
// 2.不让直接输入url路径进入网页
// 3.通过设置条件实现各种功能
router.beforeEach((to, from, next) => {
  // console.log(to, from); //刷新后 to:/homepage from:/
  // 获取token值用来做判断条件
  const token = Cookies.get("token");
  // 重新获取当前登录用户的信息
  // 当存在token并且store.state.menus没有数据的时候(长度为0),进入
  if (token && store.state.menus.length === 0) {
    // 发起请求获取数据
    getAdminInfo().then((res) => {
      if (res.code === 200) {
        // 使用updateMenus将请求回来的数据更新到vuex里面
        store.commit("updateMenus", res.data.menus);
        // 调用封装动态路由
        genRoutesConfig();
        // 出口出去到当前页面,回到当前页面后,条件不成立不进入这条路线
        next(to);
      }
    });
    // 当存在token并且路径是从/login来的 去到/home 会进入该判断 home为不存在的页面,为的是让第一次登录进来的数据先通过这里进入,然后再去到index主页,让数据一定更新到主页上
  } else if (token && from.path === "/login" && to.path === "/home") {
    // 调用封装动态路由
    genRoutesConfig();
    // 去到index主页
    next("/index");
    // 如果不存在token并且去的路径不是/login,跳转到/login.为什么要设置这个判断呢?因为不想用户手动删除token后刷新依然在非登录页,还有就是直接跳过login页直接输入url进来的
  } else if (!token && to.path !== "/login") {
    // 去到login主页
    next("/login");
    // 当存在token并且要去到/login时候的判断,明明是通过登录页登录进来了,还在url输入/login跳转回登录页,这样会存在两个token可能会对后面有影响,也不符合逻辑,所以当有token的时候想通过url跳转打login,就让他原地踏步就好
  } else if (token && to.path === "/login") {
    // 去到当前页面
    next(from);
    // 当以上判断都不成立的时候,就实行,路由守卫一定要有next()出口的,不然一直出不去
  } else {
    next();
  }
});
// export default router
export const initRouter = (app: App<Element>) => {
  app.use(router);
};

posted on 2022-05-05 10:21  冯沫流  阅读(1094)  评论(0编辑  收藏  举报