注释: 代码实现过程借鉴了海军大哥的代码
vue动态路由分俩种情况
- 第一种是前端实现, 前端通过不同角色对路由进行筛选,之后在侧边栏进行展示
- 第二种是后端实现,登录之后通过后端返回的menuList,在前端进行解析
今天主要讲解第二种情况
登录部分代码 (登录接口以及返回路由结果均有mock实现)
file: @/views/login
onSubmit (a) {
login(a).then(res => {
const { name, photo, token } = res.data // 结构
sessionStorage.setItem('token', token)
this.$store.commit('SET_NAME', name)
this.$store.commit('SET_PHOTO', photo)
this.$store.commit('SET_TOKEN', token)
this.$store.dispatch('setMenuList') // 调用方法对路由解析
this.$router.push('/home')
})
}
通过调用vuex中setMenuList的方法对后端返回的路由进行解析
file:@/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import router, { constantRoutes } from '../router/index'
// getMenu 解析后台路由
import { getMenu } from '../utils/getMenu'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
meunList: []
},
mutations: {
SET_ROUTER_MENULIST (state, list) {
// 静态路由 + 动态路由 合并 完整路由
const array = constantRoutes.concat(list)
state.meunList = array
router.options.routes = array
/**
* 新版router方法 废弃了router.addRoutes方法
*/
array.forEach(itemRouter => {
router.addRoute(itemRouter)
})
const errorPage = {
path: '*',
redirect: '/404',
hidden: true
}
/** 刷新界面进入404解决:
*原因在于,我们在addRoutes加动态路由前,就配置了通配符404路由;
* 最后改成把动态添加过路由后吗,再最后push一下404通配符
* 这之前有一个bug 如果不在addroute之后push一次通配符 在动态路由界面刷新就会进入404界面
*/
array.push(errorPage)
router.addRoute(array[array.length - 1])
}
},
actions: {
setMenuList ({ commit, state }) {
// 接收返回来的 路由数组
return new Promise((resolve, reject) => {
getMenu().then(res => { // getMenu接下来会写
commit('SET_ROUTER_MENULIST', res)
// resolve(res)
})
})
}
}
})
getMenu主要用来解析后台返回的结果
file: @/utils/getMenu.js
/* eslint-disable no-unused-vars */
import Layout from '@/layout'
import { login } from '@/api/login' // 登录接口
/**
* @description: 解析后端返回来的菜单树
* @param {*} data 后端返回来的路由树
* @param {*} arr 菜单
* @return {*}
*/
function tree (data, arr) {
// console.log(data);
data.forEach((datas, index) => {
arr.push({
path: datas.path,
name: datas.name,
hidden: !!datas.hidden,
// types: datas.types,
// hidden: datas.hidden == 'true' ? true : false,
// 当时这块踩坑了
component: datas.component === 'Layout' ? Layout : resolve => require([`@/views/${datas.component}`], resolve),
meta: {
title: datas.meta.title || '',
icon: datas.meta.icon || '',
path: datas.meta.path || ''
// // 用来存放按钮权限
// button: datas.meta.button
},
redirect: datas.redirect || '',
// id: datas.id,
// 子路由
children: []
})
// console.log(arr);
if (datas.children) {
const childArr = tree(datas.children, [])
arr[index].children = childArr
}
})
return arr
}
/**
* @description: 获取当前登录用户的菜单
* @param {*}
* @return {*}
*/
export function getMenu () {
return new Promise(function (resolve, reject) {
var token = sessionStorage.getItem('token')
var userData
if (token === 'admin') {
userData = {
account: 'wjc',
password: '000919'
}
} else {
userData = {
account: 'test',
password: 'test'
}
}
login(userData).then(res => {
const datas = res.data.rightList
// 调用 tree 来解析后端返回来的树
resolve(tree(datas, []))
})
})
}
login 为登录接口 账号密码写死了 通过不同token对应不同账号获得不同的路由
login接口代码(mock)
file: @/mock/login
export default {
/** 用户登录
*@login
*/
login: (config) => {
const user = getQueryParameters(config)
if (user.account === 'wjc' && user.password === '000919') {
return {
name: '管理员',
token: 'admin',
photo: 'https://img1.baidu.com/it/u=3364871237,1751868068&fm=15&fmt=auto',
rightList: [
{
path: '/home',
name: 'home',
redirect: '/home',
component: 'Layout',
meta: {
icon: 'el-icon-s-home',
title: 'Dashboard',
path: '/home'
},
children: [
{
path: '/home',
name: '',
component: 'home',
meta: {
icon: 'el-icon-s-home',
title: 'Dashboard',
path: '/home'
}
}
]
},
{
path: '/dataCenter',
name: '',
component: 'Layout',
redirect: '/table',
meta: {
icon: 'el-icon-s-data',
title: '基本组件'
},
children: [
{
path: '/table',
name: '',
component: 'dataCenter/table',
meta: {
title: '动态表格',
path: '/table'
},
children: []
},
{
path: '/form',
name: '',
component: 'dataCenter/form',
meta: {
title: '动态表单',
path: '/form'
},
children: []
}
]
},
{
path: '/mark',
name: '',
component: 'Layout',
redirect: '/editmark',
meta: {
icon: 'el-icon-menu',
title: 'Markdown'
},
children: [
{
path: '/editmark',
name: '',
component: 'mark/editmark',
meta: {
title: '编辑Markdown',
path: '/editmark'
},
children: []
},
{
path: '/showmark',
name: '',
component: 'mark/showmark',
meta: {
title: '展示Markdown',
path: '/showmark'
},
children: []
}
]
},
{
path: '/rolebutton',
name: 'rolebutton',
component: 'Layout',
redirect: '/rolebutton',
meta: {
icon: 'el-icon-mouse',
title: '指令按钮',
path: '/rolebutton'
},
children: [
{
path: '/rolebutton',
name: '',
component: 'rolebutton',
meta: {
icon: 'el-icon-mouse',
title: '指令按钮',
path: '/rolebutton'
}
}
]
},
{
path: '/drawingbed',
name: 'drawingbed',
component: 'Layout',
redirect: '/drawingbed',
meta: {
icon: 'el-icon-picture',
title: '图床组件',
path: '/drawingbed'
},
children: [
{
path: '/drawingbed',
name: '',
component: 'drawingbed',
meta: {
icon: 'el-icon-picture',
title: '图床组件',
path: '/drawingbed'
}
}
]
},
{
path: '/power',
name: 'power',
component: 'Layout',
redirect: '/power',
meta: {
icon: 'el-icon-s-tools',
title: '权限页面',
path: '/power'
},
children: [
{
path: '/power',
name: '',
component: 'power',
meta: {
icon: 'el-icon-s-tools',
title: '权限页面',
path: '/power'
}
}
]
}
]
}
} else {
return {
name: '测试员',
role: 0,
token: 'test',
photo: 'https://img0.baidu.com/it/u=1244881529,3297907499&fm=26&fmt=auto',
rightList: [
{
path: '/home',
name: 'home',
redirect: '/home',
component: 'Layout',
meta: {
icon: 'el-icon-s-home',
title: 'Dashboard',
path: '/home'
},
children: [
{
path: '/home',
name: '',
component: 'home',
meta: {
icon: 'el-icon-s-home',
title: 'Dashboard',
path: '/home'
}
}
]
},
{
path: '/dataCenter',
name: '',
component: 'Layout',
redirect: '/table',
meta: {
icon: 'el-icon-s-data',
title: '基本组件'
},
children: [
{
path: '/table',
name: '',
component: 'dataCenter/table',
meta: {
title: '动态表格',
path: '/table'
},
children: []
},
{
path: '/form',
name: '',
component: 'dataCenter/form',
meta: {
title: '动态表单',
path: '/form'
},
children: []
}
]
},
{
path: '/mark',
name: '',
component: 'Layout',
redirect: '/editmark',
meta: {
icon: 'el-icon-menu',
title: 'Markdown'
},
children: [
{
path: '/editmark',
name: '',
component: 'mark/editmark',
meta: {
title: '编辑Markdown',
path: '/editmark'
},
children: []
},
{
path: '/showmark',
name: '',
component: 'mark/showmark',
meta: {
title: '展示Markdown',
path: '/showmark'
},
children: []
}
]
},
{
path: '/rolebutton',
name: 'rolebutton',
component: 'Layout',
redirect: '/rolebutton',
meta: {
icon: 'el-icon-mouse',
title: '指令按钮',
path: '/rolebutton'
},
children: [
{
path: '/rolebutton',
name: '',
component: 'rolebutton',
meta: {
icon: 'el-icon-mouse',
title: '指令按钮',
path: '/rolebutton'
}
}
]
},
{
path: '/drawingbed',
name: 'drawingbed',
component: 'Layout',
redirect: '/drawingbed',
meta: {
icon: 'el-icon-picture',
title: '图床组件',
path: '/drawingbed'
},
children: [
{
path: '/drawingbed',
name: '',
component: 'drawingbed',
meta: {
icon: 'el-icon-picture',
title: '图床组件',
path: '/drawingbed'
}
}
]
}
]
}
}
}
}
router里面只需要放一些静态路由就行 注意!!! 不能把通配符路由放进静态路由 刷新页面会进入404 通配符路由一定要最后push以下,解释在上面
file: @/router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
export const constantRoutes = [
{
path: '/',
redirect: '/login',
hidden: true
},
{
path: '/login',
name: 'login',
component: () => import('@/views/login'),
hidden: true
},
{
path: '/404',
name: '404',
component: () => import('@/views/404'),
hidden: true
}
]
const createRouter = () => new VueRouter({
mode: 'history',
// 解决vue框架页面跳转有白色不可追踪色块的bug
scrollBehavior (to, from, savedPosition) {
return { x: 0, y: 0 }
},
routes: constantRoutes
})
const router = createRouter()
export default router