zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    linux下搭建lamp环境以及安装swoole扩展
    TP5 中引入第三方类库
    thinkphp5 查询的数据是对象时,获取原始数据方法
    thinkphp5 列表页数据分页查询3-带搜索条件
    thinkphp5 列表页数据分页查询2-带搜索条件
    thinkphp5 列表页数据分页查询-带搜索条件
    thinkphp5 怎么获取当前的模块,控制器和方法名
    限定页面执行时间,请求超时抛出异常或提示
    centos安装netcat
    redis在PHP中的基本使用案例
  • 原文地址:https://www.cnblogs.com/ygyy/p/14956949.html
Copyright © 2011-2022 走看看