# 路由改造

路由数据处理路由改造菜单渲染 是整个开发步骤的核心部分。路由改造 时,需要开发者理清其完整的思路,手动添加相关路由 并适时 初始化路由表:

调试

路由改造 中,我们将对 路由表路由挂载 进行改造,开发过程中会产生众多临时 bug,需要不断调试

标准的调试过程 →

# libs > router-util.js

# 函数 dynamicRouterAdd:加载路由菜单,从 localStorage 拿到路由,在创建路由时使用

import { localRead } from '@/libs/util'

// 加载路由菜单,从localStorage拿到路由,在创建路由时使用
export const dynamicRouterAdd = (from) => {
  let data = localRead('dynamicRouter-template')
  let dynamicRouter = data !== '' ? filterAsyncRouter(JSON.parse(data)) : []
  // console.log(`动态路由数据:${from}`, dynamicRouter);
  return dynamicRouter
}

# router > routers.js

保存副本并退出登录

routers.js 路由表改动较大,建议先保存副本到 routersOrg.js,以便 对比路由表变化 或随时 恢复原始路由表,同时建议暂时 退出系统,根据后续指南 适时再登录 进行调试

# 整体改造:静态路由 + 动态路由

import Main from '@/components/main'
import { dynamicRouterAdd } from '@/libs/router-util' // 引入动态路由

// 静态路由
export const constantRouter = [
  {
    path: '/login',
    name: 'login',
    meta: { title: 'Login - 登录', hideInMenu: true },
    component: () => import('@/view/login/login.vue'),
  },
  {
    path: '/',
    name: '_home',
    redirect: '/home',
    component: Main,
    meta: { hideInMenu: true, notCache: true },
    children: [
      {
        path: '/home',
        name: 'home',
        meta: {
          hideInMenu: true,
          title: '首页',
          notCache: true,
          icon: 'md-home',
        },
        component: () => import('@/view/single-page/home'),
      },
    ],
  },
  {
    path: '/401',
    name: 'error_401',
    meta: { hideInMenu: true },
    component: () => import('@/view/error-page/401.vue'),
  },
  {
    path: '/500',
    name: 'error_500',
    meta: { hideInMenu: true },
    component: () => import('@/view/error-page/500.vue'),
  },
  {
    path: '*',
    name: 'error_404',
    meta: { hideInMenu: true },
    component: () => import('@/view/error-page/404.vue'),
  },
]

// 动态路由
export const appRouter = [...dynamicRouterAdd('router.js')]

export const routes = [...constantRouter, ...appRouter]

// 所有上面定义的路由都要写在下面输出
export default routes

routers.js 完整代码 →

# router > index.js

# routes 改为花括号导入

import {
  routes, // 总路由表
  constantRouter, // 静态路由表
} from './routers'

# 函数 refreshRoute:初始化路由表刷新

export const refreshRoute = () => {
  const routes = [...constantRouter]
  // 新路由实例matcer,赋值给旧路由实例的matcher,(相当于replaceRouter)
  router.matcher = new Router({ routes }).matcher
}

重置路由

vue-router 没有提供 remove routes 方法,因此有 2 种方法清空动态路由:

  • 法一:location.reload() 刷新页面,页面会闪,暂时不用
  • 法二:router.matcher 重置 matcher,也是我这里用到的办法

# store > module > app.js

# 1.暂时隐藏 左侧菜单,注掉 getters 中的 menuList 及相关依赖

// import routers from "@/router/routers";
...
getters: {
  // menuList: (state, getters, rootState) =>
  //   getMenuByRouter(routers, rootState.user.access),
  errorCount: state => state.errorList.length
},

# 2.getRouters 方法的 getAllMenus 执行 resolve,并监听此时的路由数据

getAllMenus(rootState.user.token).then((res) => {
  ...
  console.log('转换成组件后的路由数据:', gotRouter)
  console.log('当前路由:', router) // 监听当前路由
  resolve(gotRouter) // 执行 resolve
})

此时 刷新页面 确保路由表只保留 静态路由(若未登出则登出后刷新),看看 用户登录 后的页面:

此时的页面

此时登录后的页面有如下几点需要我们处理:

  • 1.左侧菜单在第一步已隐藏,菜单改造 见后续
  • 2.路由表为初始的 静态路由,需要往路由表添加之前 处理好的动态路由 数据

# 3.actions 追加 addRouterData,添加动态路由:

// 动态添加路由数据
addRouterData({ commit, rootState }, routes) {
  // 动态添加路由
  router.addRoutes(routes);
  console.log("添加动态路由后:", router);
},
// 获取动态路由数据
getRouters({ dispatch, commit, rootState }, routes) {
  return new Promise((resolve, reject) => {
    var gotRouter = []; // 设置动态路由
    if (localRead("dynamicRouter-template") === "") {
      /* localStorage里dynamicRouter值为空 -> 没有路由数据 -> 获取路由数据 */
      console.log("获取路由:从api");
      try {
        getAllMenus(rootState.user.token)
          .then(res => {
            ...
            console.log("转换成组件后的路由数据:", gotRouter);
            dispatch("addRouterData", gotRouter).then(res => {
              resolve(gotRouter);
            });
          })
          .catch(err => { ... });
      } catch (error) { ... }
    } else {
      /* 有路由数据 -> 直接从localStorage里面获取 */
      ...
    }
  });
}

退出登录 -> 刷新页面 -> 用户登录,再测:

路由没有添加?

router 的路由并 不是响应式 的,使用 router.addRoutes 添加的路由 不会添加到路由缓存 里面 😡,所以 只能读取到初始路由。这里我的办法是 手动往 router.options.routes 添加 要添加的路由

# 4.addRouterData 方法中,手动往 router.options.routes 添加 动态路由

import { routerUpdateHandle } from '@/libs/router-util'
// 动态添加路由数据 -> 首次登录挂载路由
addRouterData({ commit, rootState }, routes) {
  // 动态添加路由 - 真正添加路由(不会立刻刷新,需要手动往router.options.routes里添加数据)
  router.addRoutes(routes);
  routerUpdateHandle(routes, router); // 手动添加路由数据
  console.log("添加动态路由后:", router);
},
  • router-util.js 追加 routerUpdateHandle 方法:
// @函数: 遍历routes路由数据,手动往router.options.routes里添加数据
export const routerUpdateHandle = (routes, router) => {
  // 遍历routes
  routes.forEach((_route) => {
    /* 手动往router.options.routes里添加数据 */
    // 1.最外层有没添加的直接添加
    if (
      !router.options.routes.some(
        (_router) => _router.meta.id === _route.meta.id
      )
    ) {
      router.options.routes.push(_route)
    }
    // 2.内层路由递归添加
    const routerChildAddHandle = (array1, child2) => {
      // 遍历array1
      array1.forEach((child1) => {
        // 找到path一致的数据
        if (child1.meta.id === child2.meta.id) {
          // 遍历child2.children
          child2.children.forEach((_child2) => {
            // 比对child1.children -> 有没添加的直接添加
            if (
              !child1.children.some(
                (_child1) => _child1.meta.id === _child2.meta.id
              )
            ) {
              child1.children.push(_child2)
            }
            // 递归
            routerChildAddHandle(child1.children, _child2)
          })
        }
      })
    }
    routerChildAddHandle(router.options.routes, _route)
  })
}

老样子~退出登录 -> 刷新页面 -> 用户登录,测!

路由添加成功

动态路由添加 成功啦 😁,尽管 左侧菜单暂时隐藏 着(还需改造),但已经可以 在地址栏输入配置好的路由地址查看相应页面 啦:

# view > login > login.vue

# 引入 router > index.js 里的 refreshRoute 方法,在初始化数据时 重置路由、清空 localStorage 中的 dynamicRouter-template 数据

import { refreshRoute } from '@/router' // 路由初始化,清空动态路由
created() {
  localStorage.setItem("dynamicRouter-template", []); // 清空路由缓存数据
  refreshRoute(); // 路由重置
}
上次更新: 6/19/2020, 11:48:01 AM