使用Vue写后台管理系统踩坑记-动态路由

本来很简单的一件事,给后台差点弄得当场去世。

前言:动态路由就是根据一个json格式的数组来生成Vue中的路由表,实现动态注册。可以前端自己实现,也可以使用后台返回的路由表来生成。

坑1-----------------------------前后台字段不匹配

坑2-----------------------------转换使用异步思想,如果没有添加路由信息便开始跳转,则会出现页面跳转空白和404

说起这个,弄得自己差点就怀疑人生(唉,忍住忍住,不是后台的锅),先说明一下,路由里面,最基础的字段有path,name,component,meta。其中path为跳转时浏览器显示的路径,name为标识,component为该path对应的组件路径,meta为路由携带的信息,里面可以定义任意的字段。使用的最重要的方法为addRoutes()。

要实现一个动态路由有如下几个步骤:

1.准备一个路由表

2.将路由表转换为自己想要的数据格式

3.使用addRoutes添加

由于添加路由addRoutes是一个异步的方法,因此可以配个async和await来使用,效果更好。

 

1.准备路由表:

leftMenu: [{
        "title": "工作台",
        "path": "/home",
        "icon": "el-icon-house",
        "children": [],
        id: 1
      }, {
        "title": "借贷管理",
        "path": "/debitManage",
        "icon": "el-icon-money",
        id: 1,
        "children": [{
            "title": "提交借款初审",
            "path": "/debitManage/firstCon",
            id: 1,
            "children": [{
              "title": "新增借款",
              "path": "/debitManage/addDebitItem",
              name: "addDebitItem",
              id: 1,
              "children": []
            }, {
              "title": "新标维护",
              "path": "/debitManage/upholdNewBidItems",
              name: "addDebitItem",
              id: 1,
              "children": []
            }, {
              "title": "借款审核",
              "path": "/debitManage/firstDebitCon",
              name: "addDebitItem",
              id: 1,
              "children": []
            }]
          }, {
            "title": "上架管理",
            id: 1,
            "path": "/debitManage/secondCon",
            "children": [{
              "title": "上架初审",
              "path": "/debitManage/firstLevelAuditItems",
              name: "addDebitItem",
              id: 1,
              "children": []
            }, {
              "title": "标的上架",
              "path": "/debitManage/secondBidsGroundItems",
              name: "addDebitItem",
              id: 1,
              "children": [

              ]
            }, {
              "title": "进行中的标管理",
              "path": "/debitManage/runningBidsItems",
              name: "addDebitItem",
              id: 1,
              "children": []
            }]
          },
          {
            "title": "复审管理",
            "path": "/debitManage/thridCon",
            id: 1,
            "children": [{
              "title": "满标复审",
              "path": "/debitManage/reexAuditItems",
              name: "addDebitItem",
              id: 1,
              "children": []
            }]
          }, {
            "title": "记录查看",
            "path": "/debitManage/viewLogs",
            id: 1,
            "children": [{
              "title": "所有借款标",
              "path": "/debitManage/debitItems",
              name: "addDebitItem",
              id: 1,
              "children": []
            }, {
              "title": "投资记录",
              "path": "/debitManage/investRecords",
              name: "addDebitItem",
              id: 1,
              "children": []
            }]
          }, {
            "title": "管理标类别",
            "path": "/debitManage/manageCategory",
            id: 1,
            "children": [{
              "title": "借款标类别",
              "path": "/debitManage/debitCategory",
              name: "addDebitItem",
              id: 1,
              "children": []
            }]
          }

        ]
      }, {
        "title": "还款管理",
        "path": "/repaymentManage",
        "icon": "el-icon-bank-card",
        id: 1,
        "children": [{
            "title": "管理还款项",
            "path": "/repaymentManage/repaymentItems",
            name: "addDebitItem",
            id: 1,
            "children": []
          },
          {
            "title": "还款记录",
            "path": "/repaymentManage/repaymentRecords",
            name: "addDebitItem",
            "children": [],
            id: 1
          }
        ]
      }, {
        "title": "资金管理",
        "path": "/capitalManage",
        id: 1,
        "icon": "el-icon-wallet",
        "children": [{
          "title": "记录查看",
          "path": "/capitalManage/logsView",
          id: 1,
          "children": [{
            "title": "充值记录",
            "path": "/capitalManage/reChargeLog",
            id: 1,
            name: "addDebitItem",
            "children": []
          }, {
            "title": "提现记录",
            "path": "/capitalManage/withDrawMoneyLog",
            id: 1,
            name: "addDebitItem",
            "children": []
          }, {
            "title": "用户资金",
            "path": "/capitalManage/userCapital",
            name: "addDebitItem",
            id: 1,
            "children": []
          }, {
            "title": "平台资金",
            "path": "/capitalManage/platformCapitalLog",
            name: "addDebitItem",
            id: 1,
            "children": []
          }]
        }, {
          "title": "相关审核",
          "path": "/capitalManage/withDrawConfirm",
          id: 1,

          "children": [{
            "title": "提现审核",
            "path": "/capitalManage/withDrawCon",
            id: 1,
            name: "addDebitItem",
            "children": []
          }]
        }]
      }, {
        "title": "会员管理",
        "path": "/memberManage",
        "icon": "el-icon-user-solid",
        id: 1,
        "children": [{
            "title": "新增借款用户",
            "path": "/memberManage/addDebitUser",
            name: "addDebitItem",
            id: 1,
            "children": []
          },
          {
            "title": "投资用户管理",
            "path": "/memberManage/investUserManage",
            name: "addDebitItem",
            id: 1,
            "children": []
          },
          {
            "title": "借款用户管理",
            "path": "/memberManage/debitUserManage",
            name: "addDebitItem",
            id: 1,
            "children": []
          }
        ]
      }, {
        "title": "内容管理",
        "path": "/contentManage",
        "icon": "el-icon-s-grid",
        id: 1,
        "children": [{
            "title": "轮播管理",
            "path": "/contentManage/sliderManage",
            id: 1,
            "children": [{
              "title": "新增轮播",
              "path": "/contentManage/sliderManage/addSliderItem",
              "children": [],
              id: 1
            }]
          },
          {
            "title": "文章管理",
            "path": "/contentManage/articleManage",
            id: 1,
            "children": [{
              "title": "新增文章",
              "path": "/contentManage/articleManage/addArticleItem",
              "children": [],
              id: 1,
            }]
          },
          {
            "title": "意见反馈",
            "path": "/contentManage/feedBack",
            id: 1,
            "children": [{
              "title": "反馈处理",
              "path": "/contentManage/feedbackManage/addFeedbackItem",
              "children": [],
              id: 1,
            }, ]
          }
        ]
      }]

 

分割线:


2.在cli搭建的项目的router文件夹中替换index.js文件,新建一个index.js文件,在里面写预先定义好的静态路由,并且写上初始化路由的方法

router/index.js

import Vue from "vue";
import Router from "vue-router";
// import Layout from "@/Layout";
import Login from "@/views/Login";
Vue.use(Router);
const originalPush = Router.prototype.push;
Router.prototype.push = function push(location) {
  return originalPush.call(this, location).catch(err => err);
};

export const constRouters = [
  {
    path: "/login",
    component: Login,
    hidden: true,
    name: "login"
  }
];
const createRouter = () =>
  new Router({
    // mode: "history",
    routes: constRouters
  });

const index = createRouter();
export function resetRouter() {
  const newRouter = createRouter();
  index.matcher = newRouter.matcher;
}
export const errorRoute = [
  {
    path: "*",
    component: () => import("@/views/NotFound"),
    hidden: true,
    name: "pageNotFound",
    meta: { title: "页面不见啦" }
  },
  {
    name: "login",
    path: "/login",
    component: () => import("../views/Login")
  }
];
export default index;

3.创建一个转化路由格式的文件:asyncRouter.js

//引入公共路由
export function getAsyncRoutes(routes) {
  const res = [];
  const keys = ["path", "name", "children"];
  if (Array.isArray(routes)) {
    routes.forEach(v => {
      const newItem = {};
      if (v.path) {
        //如果m有children,代表它是二级或者n级菜单,不引入组件
        if (v.children && v.children.length > 0) {
          newItem.component = () => "";
        } else if (v.path === "/") {
          newItem.component = newItem.component = resolve => {
            require([`@/views${v.component}`], resolve);
          };
        } else {
          //如果不是,就替换
          newItem.component = resolve => {
            require([`@/views${v.path}/index`], resolve);
          };
        }
      }
      for (const key in v) {
        if (keys.includes(key)) {
        //由于没有name字段不合规范,只能替换name字段为path后面的一截
          if (key === "name") {
            newItem["name"] = v["path"].split("/")[
              v["path"].split("/").length - 1
            ];
          } else {
            newItem[key] = v[key];
            //生成标题字段
            newItem.meta = { title: v.name };
          }
          // } else {
          //   newItem["name"] = v["path"].split("/")[
          //     v["path"].split("/").length - 1
          //   ]+v.id;
          // }
        }
      }
      if (v.path) { 
        if (
          (v.children == null || v.children.length === 0) &&
          v.path !== "/home"
        ) {
          newItem["name"] = v["path"].split("/")[
            v["path"].split("/").length - 1
          ];
        }
      }
//如果有children,使用递归继续调用该方法,实现任意深度都可以转换
      if (newItem.children && newItem.children.length) {
        newItem.children = getAsyncRoutes(v.children);
      }
      res.push(newItem);
    });
  }
  return res;
}

4.与index.js同级创建一个permission.js文件,拦截并处理跳转加载

import router from "../router";
import store from "../store";
import NProgress from "nprogress";
// console.log(store);
import "nprogress/nprogress.css";
import { resetRouter } from "../router";
import { getAsyncRoutes } from "@/router/asyncRouter";
import { errorRoute } from "../router";
const whileList = ["/login"];
var update = true;
router.beforeEach(async (to, from, next) => {
  NProgress.start();
  document.title = to.meta.title;
  //获取token
  const hasToken = (await store.getters.getToken) !== "";
  // console.log("token:" + hasToken);
  if (hasToken) {
    // console.log("有没有token", hasToken);
    if (to.path === "/login" || to.path === "/") {
      next({ path: "/home" });
    } else {
      //获取vuex中保存的路由
      let hasRoutes = await store.getters.getState;
      //如果有路由则直接下一步,如果没有则需要获取路由
      //判断是不是点击刷新
      // console.log("是否有路由", hasRoutes);
      if (hasRoutes && !update) {
        next();
      } else {
        try {
          await resetRouter();
          const accessRoutes = getAsyncRoutes(await store.getters.getRoutes);
          let changedRoutes = accessRoutes.filter(v => {
            return v.path !== "/home/index";
          });
          //---------------------------------------------------===================================================
          //-----------------------------------------------------================================================
          //在这个下面添加自定义的路由,不要在index.js里面添加
          let extraRoutes = [
            //在这里写额外的路由
            {
              path: "/sliderManage/sliderManage/addSlider",
              name: "addSlider",
              meta: { title: "新增轮播" },
              component: () =>
                import(
                  "../views/contentManage/sliderManage/sliderManage/addSlider"
                )
            },
            {
              path: "/articleManage/articleManage/addArticle",
              name: "addArticle",
              meta: { title: "新增文章" },
              component: () =>
                import(
                  "../views/contentManage/articleManage/articleManage/addArticle"
                )
            },
            {
              path: "/debitManage/Maintenance",
              name: "Maintenance",
              meta: { title: "上架复审" },
              component: () =>
                import("../views/debitManage/secondBidsGroundItems/Maintenance")
            },
            {
              path: "/debitManage/RecheckAction",
              name: "RecheckAction",
              meta: { title: "复审" },
              component: () =>
                import("../views/debitManage/reexAuditItems/RecheckAction")
            },
            {
              path: "/",
              component: () => import("@/views/home/index"),
              meta: { title: "工作台" },
              name: "index"
            },
            {
              path: "/Pwd",
              name: "Pwd",
              meta: { title: "密码管理" },
              component: () =>
                import("@/components/rest/investUserManage/Pwd.vue")
            },
            {
              path: "/luser3",
              name: "luser3",
              component: () =>
                import("@/components/rest/debitUserManage/luser3")
            },
            {
              path: "/Modify",
              name: "Modify",
              component: () =>
                import("@/components/rest/investUserManage/Modify")
            },
            {
              path: "/luser4",
              name: "luser4",
              component: () =>
                import("@/components/rest/debitUserManage/luser4")
            }
          ];
          changedRoutes.push(...extraRoutes);
          //console.log("转换后的路由:", changedRoutes);
          await router.addRoutes([
            {
              path: "/home",
              component: () => import("@/Layout/Home"),
              name: "home",
              children: changedRoutes
            }
          ]);
          await store.commit("setNoRefresh");
          update = false;
          next({ ...to, replace: true });
        } catch (error) {
          next(`/login?redirect=${to.path}`);
          console.log(error);
          NProgress.done();
        }
      }
    }
  } else {
    // console.log(to.path);
    if (whileList.indexOf(to.path) !== -1) {
      next();
    } else {
      next({ path: `/login` });
      NProgress.done();
    }
  }
});
router.afterEach(async () => {
  NProgress.done();
  // console.log("导航结束");
});

文件中定义了路由的全局前置守卫,当有token并且当前已经生成路由表时才放行;如果没有路由表则要调用getAsyncRoutes方法;

注意:1.文件中引入nprogress插件,页面加载条,启动使用start方法,停止使用done方法2.页面刷新时,路由信息会被清空,需要重新添加3.使用一个状态值来说明是否已经存在路由信息4.addRoutes只接受数组,最好使用解构然后赋值;

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值