vue-elementui-admin 动态路由渲染

在官网下载vue-elementui-admin,进行二次开发,实现动态路由渲染,用户登录后,通过接口从服务端获取权限列表,然后渲染到侧边栏。

注意:此次二次开发未涉及角色(role)删选,需要角色删选权限的可以绕行

1、router.js(@/router/router.js)

定义constantRouterMap:放置所有权限都需要的路由表,例如登录页等。

// router.js
import Router from 'vue-router';
import Layout from '@/layout'
import Login from '../views/login/';

//如首页和登录页和一些不用权限的公用页面
export const constantRouterMap = [
    { path: '/login', component: Login },
    {
        path: '/',
        component: Layout,
        redirect: '/home',
        children: [{
            path: 'home',
            name: 'home',
            component: () => import('@/views/dashboard/index'),
            meta: { title: '首页12', icon: 'dashboard' }
        }]
    }
]

const createRouter = () => new Router({
    scrollBehavior: () => ({ y: 0 }),
    routes: constantRouterMap
})

const router = createRouter()
export function resetRouter() {
    const newRouter = createRouter()
    router.matcher = newRouter.matcher // reset router
}

export default router

2、permission.js(@/store/modules/permission.js)

2.1 创建文件:@/store/modules/permission.js

用于动态获取权限菜单,

2.2 将constantRouterMap加载到js中备用,将值存入vuex中管理,所以需要在index.js中注册一下:
import permission from './modules/permission'

const store = new Vuex.Store({
  modules: {
    .......,(此处是其他模块)
    permission
  },
  getters
})
2.3 将需要用到的值存储到vuex中,在getting.js中配置
const getters = {
  sidebar: state => state.app.sidebar,
  device: state => state.app.device,
  token: state => state.user.token,
  avatar: state => state.user.avatar,
  name: state => state.user.name,
  
  // 添加值
  addRouters: state => state.permission.addRouters,
  routers: state => state.permission.routers
}
export default getters
2.4 获取接口进行路由动态拼接

经测试,component不可以动态获取组件,所以可以事先将组件加载到一个map对象中,然后路由动态生成的时候直接获取对象属性值即可(也可以自己做尝试,我写的一直报错,大神可留言赐教┭┮﹏┭┮…),注意讲404页也添加到路由中。

import { constantRouterMap } from '@/router/router.js';
import Layout from '@/layout'

//获取后台路由的接口
import { getMenuList } from '@/api/router';

//提前加载组件
const map = {
    userList: () => import('@/views/user/userList'),
    nodeList: () => import('@/views/node/nodeList')
}

const state = {
    routers: constantRouterMap,
    addRouters: []
};
const mutations = {
    SET_ROUTERS: (state, routers) => {
        state.addRouters = routers;
        state.routers = constantRouterMap.concat(routers);
    }
};
let asyncRouterMap = [];
const actions = {
    GenerateRoutes({ commit, state }) {
        return new Promise(resolve => {
            if (state.addRouters && state.addRouters.length > 0) {
                resolve();
            } else {
                getMenuList().then(res => {
                    for (let i = 0; i < res.data.length; i++) {
                        let item = res.data[i];
                        let router = {
                            path: `/${item.path}`,
                            name: `${item.path}`,
                            component: Layout,
                            alwaysShow: true,
                            meta: { title: `${item.name}`, icon: `${item.icon}` },
                            children: []
                        }
                        if (item.children && item.children.length > 0) {
                            for (let j = 0; j < item.children.length; j++) {
                                let childItem = item.children[j];
                                let child = {
                                    path: `${childItem.path}`,
                                    name: `${childItem.path}`,
                                    component: map[childItem.path],
                                    meta: { title: `${childItem.name}`, icon: 'dashboard' }
                                }
                                router.children.push(child);
                            }
                        }
                        asyncRouterMap.push(router);
                    }
                    let router404 = { path: '*', redirect: '/404', hidden: true };
                    asyncRouterMap.push(router404);
                    console.log(asyncRouterMap, "asyncRouterMap");
                    commit('SET_ROUTERS', asyncRouterMap);
                    resolve();
                });
            }
        })
    }
}

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

3、permission.js

注意:在同级的main.js入口文件中使用。

App.vuemain.js同级,创建文件permission.js,通过钩子函数router.beforeEach对路由进行加工,即在router.js定义的constantRouterMap的基础上,通过router.addRoutes 添加我们获取的数据.

注意:此处的问题,如果我们不加限制直接添加动态获取的路由,会重复添加,所以要限制只加载一次,因为路由是后续生成的,当我们刷新的时候,vuex中还没有动态路由,所以会出现404的情况,所以我们定义一个函数reSetPermissionList,如果我们访问的路由不是login并且此刻我们的addRouters为空,则去加载调用permission/GenerateRoutes,去添加addRouters,完成操作以后,将vuex中的addRouter通过router.addRoutes 添加到最终渲染路由。

3.1 reSetPermissionList 防止重复加载,以及防止404的函数
const reSetPermissionList = to => {
  return new Promise((resolve, reject) => {
    console.log(store.getters.addRouters,"12345");
    if (to.path !== '/login' && store.getters.addRouters.length === 0) {
      store.dispatch('permission/GenerateRoutes').then(() => {
          router.addRoutes(store.getters.addRouters);
          resolve('permCode')
        }).catch(error => {
          resolve('permCode')
        })
    } else {
      resolve()
    }
  })
}
2、钩子函数router.beforeEach
router.beforeEach((to, from, next) => {
  NProgress.start()
  document.title = getPageTitle(to.meta.title)

  //判断是否登录
  const hasToken = getToken()

  if (hasToken) {
  //如果登录状态下还访问login,则直接定到/
    if (to.path === '/login') {
      next({ path: '/' })
      NProgress.done()
    } else {
    //登录状态下,访问to.path,调用reSetPermissionList方法
      reSetPermissionList(to).then(data => { 
        console.log(data, "data========");
        data === 'permCode' ? next({ path: to.path,加载方法,, query: to.query }) : next()
      })
    }
  } else {
	//未登录情况下,判断是否是白名单
    if (whiteList.indexOf(to.path) !== -1) {
      // in the free login whitelist, go directly
      next()
    } else {
      next(`/login?redirect=${to.path}`)
      NProgress.done()
    }
  }
})

router.afterEach(() => {
  NProgress.done()
})

4、接口数据

在这里插入图片描述

Logo

前往低代码交流专区

更多推荐