前言

  • 路由版本 ,router.3x
"vue-router": "^3.5.2",
  • 需要看router.4x 的请看这里手摸手教你实现vue的动态路由(router.v4.x版本)


整体流程

bgp半动态引入路由和纯动态引入路由 实现动态路由_前端

实现效果

不同用户登陆显示不同侧边路由导航

bgp半动态引入路由和纯动态引入路由 实现动态路由_重置_02

代码已经上传到github

代码地址

流程

1、用户登陆,获取后端返回的路由
2、使用router.addRoute动态添加到路由 文档 3、使用router.getRoutes读取路由 文档 4、注销的时候,把路由重置到登陆前的数据。

注意点

  • 路由版本:"vue-router": "^3.2.0",
  • 官方已经废弃了addRoutes
  • 目前应该使用addRoute!!!

bgp半动态引入路由和纯动态引入路由 实现动态路由_重置_03

  • 获取路由函数router.getRoutes()返回的数组不会有层级,会把子路由提到最外面一层。

核心代码介绍

//模拟后端传的路由
export const authRouter = [
  {
    path: '/allSeePage',
    name: '所有人可见',
    component: 'allSeePage' //后面我们使用require([`@/views/${view}`], resolve) 进行动态加载
  },
  {
    path: '/adminPage',
    name: '管理员可见',
    component: 'adminPage'
  }
]

我把登陆注销添加路由、方法都放在vuex内了

1、state

state: {
    userInfo: {
      userName: '',
      password: '',
      token: '',
      routerList: [] //存放后端返回的路由列表
    }
  },

2、vuex内添加路由方法 ADD_ROUTE

vuex-mutaions

mutations: {
    ADD_ROUTE(state) {
      let routerList = JSON.parse(JSON.stringify(state.userInfo.routerList))
      console.log(26, router.getRoutes().length)
      //路由未添加之前是4个,添加完之后是6个,我们用是否小于6个,来判断是否要添加
      if (router.getRoutes().length < 6) {
        routerList = filterAsyncRouter(routerList)//路由动态添加
        console.log('路由添加前', router.getRoutes())
        routerList.forEach((i) => {
          //在home父路由内添加子路由
          router.addRoute('home', i)
        })
        console.log('路由添加后', router.getRoutes())
      }
    }
}

2、登陆

主要就是读取登陆接口路由,然后把路由添加进去

  • vuex
state: {
    userInfo: {
      userName: '',
      password: '',
      token: '',
      routerList: [],//当前登陆用户的路由列表-由后端传过来
    }
 },
mutations: {
    SET_USER_INFO(state, val) {
      state.userInfo = Object.assign(state.userInfo, val)
    }
  },
actions: {
    //登陆
    login({ commit }, userInfo) {
      const { userName, password } = userInfo
      return new Promise((resolve) => {
        //模拟登陆,获取用户信息, 权限路由列表
        //假设返回的有token, 路由列表(根据不同用户返回不同)
        /**********************模拟后端传过来的路由列表----S***********************/
        let routerList = []
        if (userName === 'admin') {
          routerList = authRouter
        } else if (userName === 'commonUser') {
          routerList = [authRouter[0]]
        }
        /**********************模拟后端传过来的路由列表----E***********************/
        let token = 'testToken'
        //把用户信息存入vuex
        commit('SET_USER_INFO', {
          userName,
          password,
          token,
          routerList
        })
        //添加路由
        commit('ADD_ROUTE')
        resolve()
      })
    },
}

3、注销-重置路由

vuex-actions

actions:{
    //注销
    logout({ commit, state }) {
      return new Promise((resolve) => {
        console.log(state.userInfo.token, '注销了')
        commit('SET_USER_INFO', {
          userName: '',
          password: '',
          token: ''
        })
        //重置路由
        resetRouter() //这是路由里面的重置方法,引入的
        resolve()
      })
    },
}

4、渲染菜单

利用router.getRoutes(),获取已经添加的路由,此方法会把所有层级变为一层,子路由会有parent属性
最后渲染到页面上
在左侧导航组件内

let routeList = this.$router.getRoutes()
      //查找home路由的子路由,然后渲染出来
      this.menuList = routeList.filter(
        (i) => i.parent && i.parent.name === 'home'
      )
  • 重置路由方法
    permission.js
//路由的创建
const createRouter = () =>
  new VueRouter({
    scrollBehavior: () => ({ y: 0 }),
    routes: constantRoutes
  })
  //重置路由
export function resetRouter() {
  const newRouter = createRouter()
  router.matcher = newRouter.matcher // reset router
}

export const router = createRouter()

路由钩子函数beforeEach

流程

bgp半动态引入路由和纯动态引入路由 实现动态路由_重置_04

代码

router.beforeEach(async (to, from, next) => {
  //获取用户信息
  let { userInfo } = store.state
  const { userName } = userInfo
  console.log('用户角色', userName ? userName : '未登陆')
  //有用户信息
  if (userName) {
    await store.dispatch('addRoute')
    let { routerList } = userInfo
    //根据to.name来判断是否为动态路由, 是否有人知道还有更好的判断方法?
    if (!to.name) {
      //当前路由是动态的,确定是有的, 有就跳自己,没有就跳404
      if (routerList.findIndex((i) => i.path === to.path) !== -1) {
        next({ ...to, replace: true })
      } else {
        next('/404')
      }
    } else {
      next()
    }
  }
  //无用户信息
  else {
    //没有权限访问,跳入没有权限页面/或者登陆页面
    // 跳转之前要判断一下是否为需要跳转的界面,不然会进入死循环
    if (to.path === '/login') {
      next()
    } else {
      Message.error('请先登陆!')
      next('/login')
    }
  }
})

路由动态component引入

export const loadView = (view) => {
  // 路由懒加载
  return (resolve) => require([`@/views/${view}`], resolve)
}

遇到的坑

1、在vue-route:3x版本内,废弃了router.addRoutes,而是使用router.addRoute,注意没有s 2、router.getRoutes获取的路由层级只有一层!不会出现子路由,子路由会有parent属性。
3、永远不要使用this.$router.options.routes来获取路由,因为动态修改路由这里面不会变化,真的是坑啊!!
4、路由f5刷新后,之前动态添加的路由都会丢失。。
5、404页面,钩子函数内进行判断就好。 不要写这句 { path: '*', redirect: '/404' }