方案思路:
1、在vue-router中通过router.beforeEach做路由拦截;
2、判断有没有登录,通过next({ path: "/login" })跳到登录页面;
3、登录成功回到首页、通过同步的方式获取权限列表,存放到vuex的state.routes中;
store.dispatch("getRoutersByRole")
content.commit('setRoutes', resp.data)
4、功能权限列表生成路由视图
获取权限列表
store.state.routes
变量列表生成路由视图
router.addRoute(menu)
5、添加404页面
一、vuex
import Vue from 'vue'
import Vuex from 'vuex'
import httpClient from '../utils/httpClient.js'
import createPersistedState from 'vuex-persistedstate'
Vue.use(Vuex)
//配置部分状态持久化,默认存储在localStorage
const PERSIST_PATHS = ['isLogin']
export default new Vuex.Store({
plugins: [createPersistedState({ paths: PERSIST_PATHS })],
state: {
isLogin: false,
routes: []
},
mutations: {
logout(state) {
state.isLogin = false;
state.routes = [];
localStorage.removeItem('token')
},
login(state, token) {
localStorage.setItem("token", token)
state.isLogin = true
},
setRoutes(state, routes) {
state.routes = routes;
},
},
actions: {
getRoutersByRole(content) {
return new Promise(resolve => {
httpClient.get("/getRouters").then(resp => {
if (resp.code == 200) {
if (process.env.NODE_ENV == 'dev') {
resp.data.push({
path: '/menu',
meta: {
title: '开发管理',
},
children: [{
path: 'menu',
name: 'menu',
meta: {
title: '菜单管理'
}
},
{
path: 'example',
name: 'example',
meta: {
title: '使用示例',
}
}
]
})
}
content.commit('setRoutes', resp.data)
resolve(true);
}
})
})
}
},
})
二、vue-router
import Vue from 'vue'
import VueRouter from 'vue-router'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import store from '../store'
import login from '../views/login.vue'
NProgress.configure({ showSpinner: false })
Vue.use(VueRouter)
const routes = [{
path: '/',
name: 'login',
redirect: '/login'
},
{
path: '/login',
name: 'login',
component: login
},
{
path: '/404',
name: '404',
component: () => import('@/views/404/index')
},
]
// 解决Vue-Router升级导致的Uncaught(in promise) navigation guard问题("3.0.2"以下没有问题)
const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(location, onResolve, onReject) {
if (onResolve || onReject) return originalPush.call(this, location, onResolve, onReject)
return originalPush.call(this, location).catch(err => err)
}
VueRouter.prototype.replace = function replace(location, onResolve, onReject) {
if (onResolve || onReject) return originalPush.call(this, location, onResolve, onReject)
return originalPush.call(this, location).catch(err => err)
}
const router = new VueRouter({
mode: "history",
routes
})
router.beforeEach(async (to, from, next) => {
console.log(to.path);
NProgress.start();
if (localStorage.getItem("token")) { //没有toeken就跳到登录页
if (store.state.routes.length > 0) {
next()
} else {
await store.dispatch("getRoutersByRole")
addRemoteroutes();
next({ ...to, replace: true }) //由于路由获取是异步的,在没有生成路由视图之前(重新加载直到路由视图完成)
}
} else {
if (to.path == "/login") { //当前路由是登录就放行,否则重定向到登录页(目的是拦截没有登录的时候输入不合法的路由)
next()
} else {
next({ path: "/login" })
}
}
})
function addRemoteroutes() {
genetaeRoutes(store.state.routes);
router.addRoute({
path: '*',
redirect: '404',
})
console.log(router.matcher.getRoutes());
}
//生产路由视图
function genetaeRoutes(Remoteroutes) {
Remoteroutes.forEach(item => {
let menu = {
path: item.path,
name: item.name,
component: main,
children: [],
redirect: ''
}
if (item.children) {
menu.children = item.children.map(item2 => {
return {
path: item2.path,
name: item2.name,
meta: item2.meta,
component: () => import(`@/views${item.path}/${item2.path}`)
}
})
menu.redirect=item.path+'/'+item.children[0].path
}
router.addRoute(menu);
})
}
router.afterEach(() => {
NProgress.done()
})
export default router
三、根据权限列表生成菜单:
setMenus() {
let temp = [];
this.$store.state.routes.forEach(item => {
if (!item.hidden) {
let menu = {}
if (item.children.length > 1) {
menu.icon = this.icons["summary"] //item.path;
menu.imeName = item.meta.title;
let subMenu = [];
item.children.forEach(subItem => {
if (!subItem.hidden) {
let sub = {}
sub.imeName = subItem.meta.title;
sub.path =item.path+"/"+ subItem.path;
subMenu.push(sub)
}
})
menu.subMenu = subMenu
} else {
menu.icon = this.icons["summary"];
menu.imeName = item.children[0].meta.title;
menu.path = item.children[0].path;
}
temp.push(menu);
}
this.menus = temp;
})
},