• vue 动态路由配置,路由由后台返回


    最近做的后台管理项目,页面路由是单独有一个操作页面管理,增加修改删除,所以路由就需要做成动态的.由后台保存,登录时获取加载,这里把方法记录下来
    这里用的项目代码是git上一位大神的项目,GitHub地址:https://github.com/PanJiaChen/vue-element-admin,是一个很优秀的后台管理项目,大家可以下载下来看下

    动态路由主要是两点,一是需要从后台获取路由,二是在什么时候把异步获取的路由添加进去
     
    需要改动的文件,以这个项目目录为例
    router>index.js
    import Vue from 'vue'
    import Router from 'vue-router'
    
    Vue.use(Router)
    
    /* Layout */
    import Layout from '@/layout'
    
    // 静态路由,这里写好一些不需要从后台获取的路由,如首页,404页面
    export const constantRoutes = [
      {
        path: '/login',
        component: () => import('@/views/login/index'),
        hidden: true
      },
      {
        path: '/404',
        component: () => import('@/views/error-page/404'),
        hidden: true
      }
      ....
    ]
    
    const createRouter = () => new Router({
      scrollBehavior: () => ({ y: 0 }),
      routes: constantRoutes
    })
    
    const router = createRouter()
    
    // 重置路由
    export function resetRouter() {
      const newRouter = createRouter()
      router.matcher = newRouter.matcher // reset router
    }
    
    export default router
    一般把获取路由,路由的方法放在vuex中
    store>modules>permission.js
    import { constantRoutes } from '@/router'
    import { getRoutes } from '@/api/role' // 获取路由的接口方法
    import Layout from '@/layout'
    
    /**
     * Use meta.role to determine if the current user has permission
     * @param roles
     * @param route
     */
    function hasPermission(roles, route) {
      if (route.meta && route.meta.roles) {
        return roles.some(role => route.meta.roles.includes(role))
      } else {
        return true
      }
    }
    
    /**
     * 把后台返回菜单组装成routes要求的格式
     * @param {*} routes
     */
    export function getAsyncRoutes(routes) {
      const res = []
      const keys = ['path', 'name', 'children', 'redirect', 'alwaysShow', 'meta', 'hidden']
      routes.forEach(item => {
        const newItem = {}
        if (item.component) {
          if (item.component === 'layout/Layout') {
            newItem.component = Layout
          } else {
            newItem.component = () => import(`@/${item.component}`)
          }
        }
        for (const key in item) {
          if (keys.includes(key)) {
            newItem[key] = item[key]
          }
        }
        if (newItem.children && newItem.children.length) {
          newItem.children = getAsyncRoutes(item.children)
        }
        res.push(newItem)
      })
      return res
    }
    
    /**
     * Filter asynchronous routing tables by recursion
     * @param routes asyncRoutes
     * @param roles
     */
    export function filterAsyncRoutes(routes, roles) {
      const res = []
    
      routes.forEach(route => {
        const tmp = { ...route }
        if (hasPermission(roles, tmp)) {
          if (tmp.children) {
            tmp.children = filterAsyncRoutes(tmp.children, roles)
          }
          res.push(tmp)
        }
      })
    
      return res
    }
    
    const state = {
      routes: [],
      addRoutes: []
    }
    
    const mutations = {
      SET_ROUTES: (state, routes) => {
        state.addRoutes = routes
        state.routes = constantRoutes.concat(routes)
      }
    }
    
    const actions = {
      generateRoutes({ commit }, roles) {
        return new Promise(async resolve => {
          let accessedRoutes
          const routes = await getRoutes() // 获取到后台路由
          const asyncRoutes = getAsyncRoutes(routes.data) // 对路由格式进行处理
          console.log(33, routes, asyncRoutes)
          if (roles.includes('admin')) {
            accessedRoutes = asyncRoutes || []
          } else { // 这里是有做权限过滤的,如果不需要就不用
            accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
          }
          commit('SET_ROUTES', accessedRoutes)
          resolve(accessedRoutes)
        })
      }
    }
    
    export default {
      namespaced: true,
      state,
      mutations,
      actions
    }
    拿到异步路由后,需要在路由拦截中加入
    permission.js
    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'
    
    NProgress.configure({ showSpinner: false }) // NProgress Configuration
    
    const whiteList = ['/login', '/auth-redirect'] // 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 {
          // determine whether the user has obtained his permission roles through getInfo
          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')
    
              // 在这里获取异步路由
              const accessRoutes = await store.dispatch('permission/generateRoutes', roles)
              // 调用router.addRoutes方法,将异步路由添加进去
              router.addRoutes(accessRoutes)
              // console.log(44, router)
    
              // 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()
            }
          }
        }
      } 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()
    })
    后台接口数据(这个项目是用mock模拟的,实际你替换一下接口地址就行)
    后台的数据格式参考这个格式
    export const asyncRoutes = [
      {
        path: '/permission',
        component: 'layout/Layout',
        redirect: '/permission/index',
        alwaysShow: true,
        meta: {
          title: 'Permission',
          icon: 'lock',
          roles: ['admin', 'editor']
        },
        children: [
          {
            path: 'page',
            component: 'views/permission/page',
            name: 'PagePermission',
            meta: {
              title: 'Page Permission',
              roles: ['admin']
            }
          },
          {
            path: 'directive',
            component: 'views/permission/directive',
            name: 'DirectivePermission',
            meta: {
              title: 'Directive Permission'
            }
          },
          {
            path: 'role',
            component: 'views/permission/role',
            name: 'RolePermission',
            meta: {
              title: 'Role Permission',
              roles: ['admin']
            }
          }
        ]
      },
    
      {
        path: '/icon',
        component: 'layout/Layout',
        children: [
          {
            path: 'index',
            component: 'views/icons/index',
            name: 'Icons',
            meta: { title: 'Icons', icon: 'icon', noCache: true }
          }
        ]
      }
    ]
    这个文件改下,之前返回的是全部的路由,现在只需要异步路由
    mock>role>index.js
    export default [
      // mock get all routes form server
      {
        url: '/vue-element-admin/routes',
        type: 'get',
        response: _ => {
          return {
            code: 20000,
            data: asyncRoutes
          }
        }
      }
    ]
    到这里就OK了,总结一下:
    1. 路由文件中把需要从后台获取的路由都删除,只留下静态路由

    2. 在vuex中定义一个路由模块,state存放路由,action获取路由,将获取路由的方法放在actions中

    3. 在路由拦截router.beforeEach方法中,调用vuex中的获取路由方法拿到异步路由,调用router.addRoutes方法,将异步路由添加进去



    这里补充一下,使用这个项目添加动态路由时由于babel-eslint的版本问题,不支持newItem.component = () => import(`@/${item.component}`)这种写法,页面空白,控制台报错
    Module build failed (from ./node_modules/_eslint-loader@2.2.1@eslint-loader/index.js): TypeError: Cannot read property 'range' of null

    我把这个版本改成推荐的稳定版7.2.3之后就可以了
    你们可以直接修改package包的版本后再install,不然删包之后再下载可能有缓存,我就是这样,一番折腾
  • 相关阅读:
    edge.js架起node.js和.net互操作桥梁
    Swift学习:闭包(Closures)
    swift UIAlertController教程
    linux配置IP的方法
    centos 6.5安装vncserver 并开启远程桌面
    CSS中各种居中方法
    jquery中的index方法和eq方法
    line-height的用法(一)
    第八章—BOM(一)
    第四章—变量,作用域和内存问题(一)
  • 原文地址:https://www.cnblogs.com/steamed-twisted-roll/p/12705041.html
Copyright © 2020-2023  润新知