vue

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

2020-08-05  本文已影响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
这样就大功告成了!
上一篇下一篇

猜你喜欢

热点阅读