1、做法

在项目接手时候想的还是根据花裤衩大佬的方法进行,后端返回异步路由进行加载。后来和后端一起确认并且查阅了其他项目做法后,采用的是所有路由在前端的异步路由中进行对比查找赋值,再通过动态路由添加。

2、思路

在用户进行登录时候,在路由守卫中调用后端接口返回该用户的相关权限列表,权限按钮、权限名称。再根据相关权限进行查找赋与addrouters

3、判断逻辑:

所有的都在路由守卫中进行,不存储在本地缓存中

3.1首先判断有无token,

如果不存在token  判断是不是在白名单中 如果在白名单中就放行,不然就跳转到登录页

3.2如果存在token,判断有无权限名称。

                             存在权限名 放行(这一步是在用户登录成功后的所有逻辑)

                             不存在权限名称,进行查询,调用vuex中的获取用户权限登录数据

                              查询到数据后,将权限名称、菜单列表、按钮列表存入vuex中

因为有一个管理员,如果他的权限名称为管理员,赋予本地的全部asyncRouters,不进行判断。

如果是其他权限名称。就将拿到的菜单列表与异步路由进行对比赋值,再添加到动态路由中

4、代码

// 导航守卫
router.beforeEach(async (to, from, next) => {
  // document.title = getTitle(to.meta.title)
  //如果去登录页进行跳转
  if (to.path === '/login') {
    // 如果login 页面没有重定向 手动重定向
    if (!Object.keys(to.query).length) {
      next({
        path: '/login',
        query: {
          redirect: '/'
        }
      })
    } else {
      next()
    }
  } else {
    //查询有没有token
    if (store.getters.token) {
      const roleName = store.getters.roleName
      //这里判断是否有一级菜单导航
      //判断有无权限名 有就放行
      if (roleName) {
        next()
      } else {
        // 没有权限名进行api调用,获取当前用户所拥有权限
        try {
          //try执行一些可能会抛出的错误
          // 这是一个错误处理机制,用于捕获 JavaScript 代码中的错误并执行相应的处理程序,catch() 方法接受一个函数作为参数,该函数在发生错误时被调用并传递错误消息作为参数
        // 将接口查询到的东西都存入vuex中
          const data = await store.dispatch('user/_getInfo')
          const menuList = store.getters.menuList
        //  将获取到的菜单列表与本地的路由进行对比赛选
          const addRoutes = await store.dispatch(
            'permission/getAsyncRoutes',
            menuList
          )
          router.addRoutes(addRoutes)
          next({ ...to, replace: true })
        } catch (error) {
          // 抛出错误
          if (error) {
            Message.error(error)
          }
        }
      }
    } else if (whiteList.indexOf(to.path) !== -1) {
      next()
    } else {
      next({
        path: '/login',
        query: {
          redirect: to.fullPath
        }
      })
    }
  }
})

user的vuex

  //获取后端接口得到用户登录权限数据
  _getInfo({ commit }) {
    return new Promise((resolve, reject) => {
      getInfo()
        .then(res => {
          if (res.data) {
            // 如果查询成功了跳转到主页
            router.push('/home')
            //结构权限名与菜单列表、按钮列表
            const { roleName, menuList, permissionList } = res.data
            //2将用户数据储存到vuex里面用于使用时取值
            commit('SET_ROLE_NAME', roleName)
            commit('SET_MENU_LIST', menuList)
            commit('SET_PERMISSION_LIST', permissionList)
          } else {
            Message.error(res.msg)
          }
          resolve(res.data)
        })
        .catch(error => {
          if (error.msg) {
            Message.error(error.msg)
          }
          reject(error)
        })
    })
  }
  SET_ROLE_NAME(state, payload) {
    state.roleName = payload
  },

  SET_INTRODUCE(state, payload) {
    state.introduce = payload
  },
  SET_MENU_LIST(state, payload) {
    state.menuList = payload
  },
  SET_PERMISSION_LIST(state, payload) {
    state.permissionList = payload
  }

最重要的路由处理因为后端返回的都是权限名称,所以用不到树状结构数据

import { asyncRoutes, currencyRoutes } from '@/router'

const state = {
  routes: [],
  addRoutes: []
}
const mutations = {
  SET_ROUTES(state, payload) {
    // 存入整合后的所有路由方便后续使用
    state.routes = [...currencyRoutes, ...payload]
    // 需要动态路由添加的路由
    state.addRoutes = payload
  }
}
//遍历asyncRoutes动态路由
function forSearchArr(route, routerName) {
  let arrNew = []
  for (let item of route) {
    // 将其复制到一个新的对象中,从而实现对象的浅拷贝(只拷贝对象中的属性,而不包括属性所引用的对象)
    let itemNew = { ...item } 
    // includes() 是 JavaScript 中字符串、数组和类数组对象内置的方法之一,用于判断一个对象中是否包含指定的元素。
    // 对于字符串和数组对象,该方法会遍历整个对象,判断其中是否包含指定的元素,返回一个布尔值用于表示结果。
    // 对于类数组对象,该方法会将其转换为数组对象后再进行比较
    if (routerName.includes(itemNew.name)) {
      // 如果存在子元素,进行递归调用
      if (itemNew.children) {
        itemNew.children = forSearchArr(itemNew.children, routerName)
      }
      arrNew.push(itemNew)
    }
  }
  return arrNew
}

const actions = {
  getAsyncRoutes({ commit, rootGetters }, menuList) {
    return new Promise(resolve => {
      let routes = []
      // 管理员拥有所有的路由,菜单权限
      if (rootGetters.roleName === '管理员') {
        routes = asyncRoutes || ''
      } else {
        // 不是管理员,进行异步路由和获取的菜单列表进行对比重组
        routes = forSearchArr(asyncRoutes, menuList)
      }
      commit('SET_ROUTES', routes)
      resolve(routes)
    })
  }
}
export default {
  namespaced: true,
  state,
  mutations,
  actions
}

Logo

前往低代码交流专区

更多推荐