美文网首页vue
使用element-admin 实现动态路由(后端控制)

使用element-admin 实现动态路由(后端控制)

作者: 如意如意呀 | 来源:发表于2020-08-05 16:06 被阅读0次

    前面我们说了,后端控制会相对安全一些。

    参考了 https://www.cnblogs.com/langhaoabcd/p/11346227.html
    解决新手容易出现的问题

    直接上代码 这个代码直接粘到element-admin就实现了动态路由

    1.在router里保留基础路由

    export const constantRoutes = [
      {
        path: '/login',
        component: () => import('@/views/login/index'),
        hidden: true
      },
      {
        path: '/404',
        component: () => import('@/views/404'),
        hidden: true
      },
      {
        path: '/',
        component: Layout,
        redirect: '/dashboard',
        children: [{
          path: 'dashboard',
          name: 'Dashboard',
          component: () => import('@/views/dashboard/index'),
          meta: { title: 'Dashboard', icon: 'dashboard' }
        }]
      },
    ]
    

    2.获取用户权限菜单,保存到vuex里

    stroe/modules/user.js中,有个getInfo方法查询用户基本信息,返回了用户的菜单列表

    // get user info
      getInfo({ commit, state }) {
        return new Promise((resolve, reject) => {
          getInfo(state.token).then(response => {
            const { data } = response
            if (!data) {
              return reject('Verification failed, please Login again.')
            }
            const { name, avatar } = data
            //这里模拟了动态获取的数据
            const menus =
            [{
              path: '/books',
              component: 'Layout',
              children: [{
                path: 'index',
                name: 'AddressBook',
                component: '/workbench/addressbook/index',
                meta: { title: '通讯录', icon: 'company' }
              }]
            },
            {
              path: '/systool',
              component: 'Layout',
              redirect: '/systool/coder',
              name: 'SysTool',
              meta: { title: '实验室', icon: 'example' },
              children: [
                {
                  path: 'calendar',
                  name: 'Calendar',
                  component: '/workbench/calendar/index',
                  meta: { title: '日程', icon: 'table' }
                }
              ]
            }]
            commit('SET_NAME', name)
            commit('SET_AVATAR', avatar)
            commit('SET_MENUS', menus)
            resolve(data)
          }).catch(error => {
            reject(error)
          })
        })
      },
    

    stroe/getters.js里加

    menus: state => state.user.menus
    

    3.动态生成权限路由(核心)

    根据环境配置导入组件,在vue中,将菜单路径作为参数,实现路由地址的注入
    在 src/router 文件夹下,建立两个文件,各只需添加一行代码, 定义导入方法

    //src/router/_import_development.js
    //开发环境导入组件
    module.exports = file => require('@/views' + file + '.vue').default // vue-loader at least v13.0.0+
    
    //src/router/_import_production.js
    //生产环境导入组件
    module.exports = file => () => import('@/views' + file + '.vue')
    

    在路由钩子中,过滤路由,并生成路由
    核心在src目录下的permission.js中,router.beforeEach路由钩子

    import router from './router'
    import store from './store'
    import {
      Message
    } from 'element-ui'
    import NProgress from 'nprogress' // progress bar
    import 'nprogress/nprogress.css' // progress bar style
    import {
      getToken
    } from '@/utils/auth' // get token from cookie
    import getPageTitle from '@/utils/get-page-title'
    import Layout from '@/layout'
    const _import = require('./router/_import_' + process.env.NODE_ENV) // 获取组件的方法
    
    NProgress.configure({
      showSpinner: false
    }) // NProgress Configuration
    
    const whiteList = ['/login'] // no redirect whitelist
    
    router.beforeEach(async(to, from, next) => {
      // start progress bar
      NProgress.start()
    
      // set page title
      document.title = getPageTitle(to.meta.title)
    
      // determine whether the user has logged in
      const hasToken = getToken()
    
      if (hasToken) {
        if (to.path === '/login') {
          // if is logged in, redirect to the home page
          next({
            path: '/'
          })
          NProgress.done()
        } else {
          const hasGetUserInfo = store.getters.name
          if (hasGetUserInfo) {
            next()
          } else {
            try {
              // get user info
              await store.dispatch('user/getInfo')
              if (store.getters.menus.length < 1) {
                global.antRouter = []
                next()
              }
              const menus = filterAsyncRouter(store.getters.menus) // 1.过滤路由
              router.addRoutes(menus) // 2.动态添加路由
              global.antRouter = menus // 3.将路由数据传递给全局变量,做侧边栏菜单渲染工作
              next({
                ...to,
                replace: true
              }) // hack方法 确保addRoutes已完成 ,set the replace
            } 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()
            }
          }
        }
      } else {
        /* has no token*/
    
        if (whiteList.indexOf(to.path) !== -1) {
          // in the free login whitelist, go directly
          next()
        } else {
          // other pages that do not have permission to access are redirected to the login page.
          next(`/login?redirect=${to.path}`)
          NProgress.done()
        }
      }
    })
    
    router.afterEach(() => {
      // finish progress bar
      NProgress.done()
    })
    
    // 遍历后台传来的路由字符串,转换为组件对象
    function filterAsyncRouter(asyncRouterMap) {
      const accessedRouters = asyncRouterMap.filter(route => {
        if (route.component) {
          if (route.component === 'Layout') {
            route.component = Layout
          } else {
            route.component = _import(route.component) // 导入组件
          }
        }
        if (route.children && route.children.length) {
          route.children = filterAsyncRouter(route.children)
        }
        return true
      })
    
      return accessedRouters
    }
    

    4.最后一步,合并路由

    合并路由.jpg

    问题

    如果你也是模拟数据,把代码粘过去就行了,没有问题
    但是如果你是从后台获取数据 你这样写可就显示不出来了


    问题.jpg

    因为这里是一个异步,所以可能后台数据还没拿到,就直接执行了下面这个函数,这里我们需要改成同步
    还有一个问题是可能刷新会跳到404,把{ path: '*', redirect: '/404', hidden: true }最好放到最后
    直接上代码


    修改.jpg
    这样就大功告成了!

    相关文章

      网友评论

        本文标题:使用element-admin 实现动态路由(后端控制)

        本文链接:https://www.haomeiwen.com/subject/raysrktx.html