基于vue-element-admin模板二次开发
先说一下最终想实现的效果。
流程为 登录->拿到角色->根据不同角色拿到不同菜单->展示。因后台还未搭好,所以菜单在暂时在前台维护,以模块的概念来替代角色的作用(根据模块展示不同菜单)
系统将会有两个模块(A和B)
一、基础路由表
以下是router的结构
equ 和 manager 是我们两个前台维护的路由表(后续会贴内容,先了解就行)。之后要动态展示的就是这两个路由表
例: 模块A显示equ中的菜单 / 模块B则显示manager中的菜单
index.js代码只需要在静态路由对象中添加不需要模块控制的路由即可,其他不需要动
export const constantRoutes = [
{
path: '/login',
component: () => import('@/views/login/index'),
hidden: true
},
{
path: '/',
component: () => import('@/views/login/index'),
hidden: true
},
{
path: '/404',
component: () => import('@/views/404'),
hidden: true
}
]
二、Vuex维护Router对象
为什么要用Vuex来维护router对象呢。主要解决两个问题
1、获取router新增的菜单(router对象中无法查看新增的路由 ps:如果有请告诉我)
2、每次刷新都能重置路由
步骤:在store/modules中新建permission.js
permission.js代码:
import { asyncRoutes, constantRoutes } from '@/router'
import Layout from '@/layout'
import equ from '@/router/asyRouter/equ'
import { getModule } from '@/utils/auth'
import manager from '@/router/asyRouter/manager'
/**
* 静态路由懒加载
* @param view 格式必须为 xxx/xxx 开头不要加斜杠
* @returns
*/
export const loadView = (view) => {
return (resolve) => require([`@/views/${view}.vue`], resolve)
}
/**
* 把从后端查询的菜单数据拼装成路由格式的数据
* @param routes
* @param data 后端返回的菜单数据
*/
export function generaMenu(routes, data) {
data.forEach(item => {
const menu = {
path: item.path,
// # 就用默认的Layout
component: item.component === '#' ? Layout : loadView(item.component),
hidden: item.status === 0, // 状态为0的隐藏
redirect: item.redirect,
children: [],
name: item.name,
meta: item.meta,
props: item.props
}
if (item.children) {
generaMenu(menu.children, item.children)
}
routes.push(menu)
})
return routes
}
const state = {
routes: [],
addRoutes: []
}
const mutations = {
SET_ROUTES: (state, routes) => {
state.addRoutes = routes
// 拼接静态路由和动态路由
state.routes = constantRoutes.concat(routes)
}
}
const actions = {
generateRoutes({ commit }, token) {
return new Promise(resolve => {
let menuData
// getModule拿到的是模块id(A或B),判断A和B
switch (getModule()) {
case 'A':
menuData = Object.assign([], equ)
break
case 'B':
menuData = Object.assign([], manager)
break
}
const tempAsyncRoutes = Object.assign([], asyncRoutes)
const accessedRoutes = generaMenu(tempAsyncRoutes, menuData)
accessedRoutes[accessedRoutes.length] = { path: '*', redirect: '/404', hidden: true }
commit('SET_ROUTES', accessedRoutes)
resolve(accessedRoutes)
})
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
getmoudule代码(这个建议自己写
const TokenKey = 'vue_admin_template_token'
const ModuleKey = 'moduleId'
import constants from '@/utils/bizConstant'
export function getToken() {
return sessionStorage.getItem(TokenKey)
}
export function setToken(token) {
return sessionStorage.setItem(TokenKey, token)
}
export function removeToken() {
return sessionStorage.removeItem(TokenKey)
}
export function getModule() {
if (sessionStorage.getItem(ModuleKey)) {
return sessionStorage.getItem(ModuleKey)
} else {
return constants.moduleList[0].value
}
return sessionStorage.getItem(ModuleKey)
}
export function setModule(token) {
return sessionStorage.setItem(ModuleKey, token)
}
export function removeModule() {
return sessionStorage.removeItem(ModuleKey)
}
export function removeAuth() {
sessionStorage.removeItem(ModuleKey)
sessionStorage.removeItem(TokenKey)
return true
}
切记改完store 要修改getter.js 和 index.js(这个不写代码了,看看Vuex)
三、修改Navbar
这样我们就可以通过Vuex对象来控制router了
四、登录获取菜单
修改代码
跳转至第一个添加的第一个菜单
五、解决刷新空白问题
修改src下的permission.js
每次刷新都store中的路由(实现动态路由)
const accessRoutes = await store.dispatch('permission/generateRoutes', store.getters.token)
router.addRoutes(accessRoutes)
next({ ...to, replace: true })
为什么要使用
next({ ...to, replace: true })
因为addRoute后直接访问可能会白屏,因为路由还没挂载到Route上,这个时候就需要replace:true来确保它挂载上去了
六、使用
this.moduleId 代表了你想切的模块,之后就可以通过模块来切换你想显示的菜单啦
setModule(this.moduleId)
store.dispatch('permission/generateRoutes', 'admin-token', { root: true }).then((accessRoutes) => {
// 必须先重置路由
resetRouter()
router.addRoutes(accessRoutes)
router.push({ name: accessRoutes[0].children[0].name })
})
注: 如需要后台控制菜单,则只需要在 vuex中(permission.js)
generateRoutes()方法下修改自己的逻辑就可以,最后把返回的对象调用一下
generaMenu()进行封装 就可以实现后台控制菜单了