vue后台管理系统的菜单权限处理

1.

在首次请求登录接口的时候,由后端返回相应的角色权限,再根据这个进行动态路由生成。

自己根据角色创建不同的路由表,然后在登录时拿 到不同的角色标记,来引入对应的路由表。

 

2.把路由表存储在vuex中,右侧菜单通过直接引入vuex存的路由表进行渲染。

通过接口返回的角色权限,根据角色来动态的通过router.addRoutes(),添加不同的路由。

 

 

3.在路由守卫router.beforeEach中进行判断

const hasRoles = store.getters.roles && store.getters.roles.length > 0
      if (hasRoles) {
        next()
      } else {
        try {
          // get user info
          // note: roles must be a object array! such as: ['admin'] or ,['developer','editor']
          const { roles } = await store.dispatch('user/getInfo')

          // generate accessible routes map based on roles
          const accessRoutes = await store.dispatch('permission/generateRoutes', roles)

          // dynamically add accessible routes
          router.addRoutes(accessRoutes)

          // hack method to ensure that addRoutes is complete
          // set the replace: true, so the navigation will not leave a history record
          next({ ...to, replace: true })
        } catch (error) {
          // remove token and go to login page to re-login
          await store.dispatch('user/resetToken')
          Message.error(error || 'Has Error')
          next(`/login?redirect=${to.path}`)
          NProgress.done()
        }
      }

 

正以为如此很多人在使用动态添加路由addRoutes()会遇到下面的情况:
在addRoutes()之后第一次访问被添加的路由会白屏,这是因为刚刚addRoutes()就立刻访问被添加的路由,然而此时addRoutes()没有执行结束,因而找不到刚刚被添加的路由导致白屏。因此需要从新访问一次路由才行。

该如何解决这个问题 ?
此时就要使用next({ ...to, replace: true })来确保addRoutes()时动态添加的路由已经被完全加载上去。

next({ ...to, replace: true })中的replace: true只是一个设置信息,告诉VUE本次操作后,不能通过浏览器后退按钮,返回前一个路由。

因此next({ ...to, replace: true })可以写成next({ ...to }),不过你应该不希望用户在addRoutes()还没有完成的时候,可以点击浏览器回退按钮搞事情吧。

其实next({ ...to })的执行很简单,它会判断:

如果参数to不能找到对应的路由的话,就再执行一次beforeEach((to, from, next)直到其中的next({ ...to})能找到对应的路由为止。

也就是说此时addRoutes()已经完成啦,找到对应的路由之后,接下来将执行前往对应路由的beforeEach((to, from, next) ,因此需要用代码来判断这一次是否就是前往对应路由的beforeEach((to, from, next),如果是,就执行next()放行。

如果守卫中没有正确的放行出口的话,会一直next({ ...to})进入死循环 !!!

因此你还需要确保在当addRoutes()已经完成时,所执行到的这一次beforeEach((to, from, next)中有一个正确的next()方向出口。

因此想实现动态添加路由的操作的话,代码应该是这样的:

router.beforeEach((to, from, next) => {
const token = sessionStorage.getItem('access_token')
// 存在 token 说明已经登录
if (token) {
// 登录过就不能访问登录界面,需要中断这一次路由守卫,执行下一次路由守卫,并且下一次守卫的to是主页'
if (to.path === '/login') {
next({ path: '/' })
}
// 保存在store中路由不为空则放行 (如果执行了刷新操作,则 store 里的路由为空,此时需要重新添加路由)
if (store.getters.getRoutes.length || to.name != null) {
//放行
next()
} else {
// 将路由添加到 store 中,用来标记已添加动态路由
store.commit('ADD_ROUTER', '需要添加的路由')
router.addRoutes('需要添加的路由')
// 如果 addRoutes 并未完成,路由守卫会一层一层的执行执行,直到 addRoutes 完成,找到对应的路由
next({ ...to, replace: true })
}
} else {
// 未登录时,注意 :在这里也许你的项目不只有 logon 不需要登录 ,register 等其他不需要登录的页面也需要处理
if (to.path !== '/logon') {
next({ path: '/logon' })
} else {
next()
}
}

 

4.在路由文件中实例化了路由,会导致在vuex中获取不到路由列表,打印undefined。最后通过(路由懒加载)路由文件中的component引入方式改为

component: () => import('@/views/clipboard/index'),解决。  (不知道什么原因获取不到??)


5.   退出或切换角色时需要路由重置,防止因为router.addroutes()导致路由重复添加

router/index.js  文件

const createRouter = () => new Router({ // mode: 'history', // require service support scrollBehavior: () => ({ y: 0 }), routes: constantRoutes }) const router = createRouter() // Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
// 退出或切换角色时需要路由重置,防止因为router.addroutes()导致路由重复添加
export function resetRouter() { //重置方法 const newRouter = createRouter() router.matcher = newRouter.matcher // reset router }

 

 6.vuex中批量引入所有的modules文件

//webpack批量引入文件

const modulesFiles = require.context('./modules', true, /\.js$/) // you do not need `import app from './modules/app'` // it will auto require all vuex module from modules file const modules = modulesFiles.keys().reduce((modules, modulePath) => { // set './app.js' => 'app' const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1') const value = modulesFiles(modulePath) modules[moduleName] = value.default return modules }, {}) const store = new Vuex.Store({ modules, getters })

 

 7. vuex namespaced的作用以及使用方式

vuex中的store分模块管理,需要在store的index.js中引入各个模块,为了解决不同模块命名冲突的问题,将不同模块的namespaced:true,之后在不同页面中引入getter、actions、mutations时,需要加上所属的模块名

 

const state = {
  token: getToken(),
  name: '',
  avatar: '',
  introduction: '',
  roles: []
}

const mutations = {
  SET_TOKEN: (state, token) => {
    state.token = token
  },
}

const actions = {
  // user login
  login({ commit }, userInfo) {
    const { username, password } = userInfo
    return new Promise((resolve, reject) => {
      login({ username: username.trim(), password: password }).then(response => {
        const { data } = response
        commit('SET_TOKEN', data.token)
        setToken(data.token)
        resolve()
      }).catch(error => {
        reject(error)
      })
    })
  },
}

export default {
  namespaced: true,
  state,
  mutations,
  actions
}

 

 8.router.addRoutes添加的动态路由,刷新页面后跳到404页面

在使用addRoutes之前我就定义了,通配符 * 跳转到404页面如下图: 这就是问题所在。
解决方法是 不要再路由中添加404页面 在addRoutes里进行拼接 (通配符 * 跳转到404页面的路由)

在beforeEach中打印 to发现是404 打印from显示是/

当页面一刷新 addRoutes 还没有添加上 路由就开始跳转了 所以找不到路由就跳转到404页面了

 

 

 

 转:https://blog.csdn.net/qq_37121488/article/details/88287066

转:https://blog.csdn.net/qq_41912398/article/details/109231418

转:https://blog.csdn.net/fuck487/article/details/83411856?utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control

posted @ 2021-06-30 23:32  炽橙子  阅读(1342)  评论(0编辑  收藏  举报