记一次vue动态路由以及菜单权限的实现思路

2021-07-23  本文已影响0人  我背井离乡了好多年

一、思路
1.首先是平级菜单,靠parentId来区分层级,每个菜单也有自己的id.
2.系统中存在角色管理模块,每个角色下都有自己所持有的菜单id.
3.用户登录成功后端返回角色,用户靠角色id去查这个角色下绑定的菜单id。
4.获取所有菜单,拿着当前角色所持有的菜单id,过滤得到可以拥有的菜单。再一递归,组织成树,存到本地待命。我强调一下,
这个菜单是拿给addRoutes用的哦,相当于还是原材料,这里我称为原材料菜单。
5.总之,在路由跳转之前,也就是router.beforeEach钩子内,得把原材料菜单处理好存在本地。跳转路由的钩子内,判断下有没有
原材料菜单,如果没有给它跳转到登录页面。有原材料菜单就取出来调用 router.addRoutes组成路由。有组织好的路由就调用next()放行。

二、关键代码截图
1.addRoutes的使用,在入口文件main.js中挂载路由权限文件。以下代码出自我的权限文件。

image.png
import router from "./index"
import store from "../store/index"

let _importRouter = require("@/router/_importRouterFile")
// 添加白名单
const whiteRouter = ['/login', '/dynamicRouter']
// 定义路由对象 这个文件这个位置只在mian.js中只会执行一次
let currentRouterArr


// 路由守卫
// 这个钩子是每次跳转路由都会执行
// 每次跳转都需要判断有没有组织好路由(currentRouterArr),指不定哪一次就被清除掉
router.beforeEach((to, from, next) => {
  // currentRouterArr只要没被赋值都是undefined
  if (localStorage.getItem("token")) {
    if (to.path === '/login') {
      localStorage.removeItem("token")
      localStorage.removeItem("personInfo")
      localStorage.removeItem("currentRouter")
      store.commit("login/SET_TOKEN", '')
      store.commit("login/SET_PERSONINFO", '')
      store.commit("login/SET_CURRENTROUTER", '')
      next()
    } else {
      // ================S==========================
      if (!currentRouterArr) {
        // 楼上是有无组织过路由的标识
        let localStorageRouter = localStorage.getItem("currentRouter") ? JSON.parse(localStorage.getItem("currentRouter")) : ''
        if (!localStorageRouter) {
          next('/login')
        } else {
          // 登录时组织好了的,现在为了把组件中的文件加上去
          localStorageRouter = localStorage.getItem("currentRouter") ? JSON.parse(localStorage.getItem("currentRouter")) : ''
          // 打个标识,标明我拼接好了路由
          currentRouterArr = JSON.parse(JSON.stringify(localStorageRouter))
          changeRouterFile(localStorageRouter)
          router.addRoutes(localStorageRouter)
          next({...to, replace: true})
        }
      } else {
        // 未在白名单之内的唯一放行路线
        next()
      }
      // ================E==========================
      // 不需要拼接动态路由时放开
      // next()
    }
  } else {
    if (whiteRouter.indexOf(to.path) !== -1) {
      next()
    } else {
      next('/login')
    }
  }
})

let changeRouterFile = router => {
  router.forEach(item => {
    if (item.component) {
      // "./layout/ModuleCommonPage.vue" 需要将组件中的./去掉,载入文件需要
      item.component = item.component.substr(2, item.component.length)
      item.component = _importRouter(item.component)
    }
    item.children && item.children.length > 0 && changeRouterFile(item.children)
  })
}

三、疑问
1、我可能会问为什么是把原材料菜单存到本地呢?
因为防止用户刷新浏览器路原材料菜单不在了啊。一旦不在了,就只能在登录的时候跑登录接口才能获取了。另外,用户一跳转到登录页或者手动点击退出,我都把本地缓存中的原材料菜单给他清除掉。
2、为什么是在登录之后跳转之前获取原材料菜单呢?
因为什么时候需要路由,登录页我是直接放出来的,登录之后我知道你是谁了就立马需要路由了。所以选择这个时候。不然,也没有其他时候适合了。

四、补充说明token
http是无状态的,每个客户端来请求,我不知道你是谁。为了知道客户端是谁,客户端得带上一个唯一标识token。
客户端拿到token也给存本地,一旦token没了,就强制退出登录。客户端的每个请求都会在请求头携带token,服务器接到请求首先判断有没有token,没有就不给你返回数据。有就解析token,知道你是谁就给你返回对应的数据。

上一篇 下一篇

猜你喜欢

热点阅读