一、根据角色权限渲染菜单
1.1 调整初始路由表
//动态路由
export const AsynctRoutes = [{..}]
//静态路由
export const constantRoutes= [{..}]
const createRouter = () => new Router({
// mode: 'history', // require service support
scrollBehavior: () => ({ y: 0 }),
// 只初始加载静态路由!
routes: [...constantRoutes]
})
1.2 筛选角色权限对应的异步路由
由于刷新页面时以及第一次登陆时都需要添加对应权限路由,故采取前置路由守卫进行处理
1.2.1 前置守卫添加对应权限路由
const whitePath = ['/login', '/404']
router.beforeEach(async (to, from, next) => {
const token = store.getters.token
if (token) {
if (to.path === '/login') {
Message.success('你已登录无需重复登录')
next('/')
} else {
// vuex 页面刷新后丢失并存储的数据
// router.addRoutes 刷新后也会丢失添加的路由
// !路由每次跳转前查看用户信息是否存在,若不存在表示页面刷新了需重新获取用户信息和重新添加动态路由。
// 第一次登陆无信息时;
// 页面刷新 => 用户信息不存在时;
if (!store.getters.name) {
// 1 获取用户信息得到用户对应角色的菜单权限
let menu = await store.dispatch('user/getUserInfoActions')
// 2 根据权限标识匹配菜单页路由
let filterRoutes = AsynctRoutes.filter((r) => {
return menu.includes(r.children[0].toLowerCase())
})
// 3 动态添加路由
router.addRoutes([...filterRoutes, { path: '*', redirect: '/404', hidden: true }])
// 4 vuex存储路由表展示菜单
store.commit("router/setRoutes", filterRoutes)
next(to.path) // 跟进跳转地址
}
// 页面无刷新 => 用户信息存在时:直接跳转
else {
next()
}
}
//无token时:
} else {
//在白名单放行;不在跳转到登录页
if (whitePath.includes(to.path)) {
next()
} else {
Message.error('登陆后才可以查看')
next('/login')
}
}
})
1.2.2 vueX 存储路由表展示菜单
// 静态路由集合
import { constantRoutes } from "@/router"
let state = () => {
return {
// 存放静态路由 + 权限对应路由 用于展示菜单
routes: constantRoutes
}
}
let mutations = {
// 合成最终菜单路由
setRoutes (state, newRoutes) {
state.routes = [...state.routes, ...newRoutes]
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
1.3 用户退出时清空动态菜单路由
addroute添加的路由无法删除导致重复添加路由的处理
#router.index.js
// 重置路由方法
export function resetRouter () {
const newRouter = createRouter()
router.matcher = newRouter.matcher // reset router
}
Vue.use(Router)
export default router
1.4 修改菜单渲染数据来源为vuex数据
<template>
<div :class="{'has-logo':showLogo}">
<logo v-if="showLogo" :collapse="isCollapse" />
<el-scrollbar wrap-class="scrollbar-wrapper">
<el-menu
:default-active="activeMenu"
:collapse="isCollapse"
:background-color="variables.menuBg"
:text-color="variables.menuText"
:unique-opened="false"
:active-text-color="variables.menuActiveText"
:collapse-transition="false"
mode="vertical"
>
<sidebar-item
v-for="route in routes"
:key="route.path"
:item="route"
:base-path="route.path"
/>
</el-menu>
</el-scrollbar>
</div>
</template>
export default {
components: { SidebarItem, Logo },
computed: {
...mapGetters([
'sidebar'
]),
routes () {
// $router.options.routes : 只得到router初始化时的路由表
// return this.$router.options.routes
// 最终的菜单
return this.$store.state.router.menus
},
}