思路:
- 通过登录不同用户向后台请求不同的权限数据
- 对用户权限做对比:请求数据 -对比- 全部路由
准备路由 (src/router/index.js)
import Vue from "vue";
import VueRouter from "vue-router";
const Login = () => import("@/views/login");
const Layout = () => import("@/components/layout/home");
const Home = () => import("@/views/home");
const NotFound = () => import("@/views/errPage/404");
Vue.use(VueRouter);
// 捕获 push replace 中的错误
// 当然在 replace 中的错误也是可以相同的进行捕获
const originalPush = VueRouter.prototype.push;
const originalReplace = VueRouter.prototype.replace;
// 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);
};
// replace
VueRouter.prototype.replace = function push(location, onResolve, onReject) {
if (onResolve || onReject)
return originalReplace.call(this, location, onResolve, onReject);
return originalReplace.call(this, location).catch((err) => err);
};
// 初始化路由
export default new VueRouter({
routes: [
{
path: "/login",
name: "login",
component: Login,
meta: {
title: "登录",
},
},
],
});
// 动态路由
export const DynamicRoutes = [
{
path: "",
name: "container",
redirect: "/home",
component: Layout,
meta: {
requiresAuth: true, // 是否需要登录
title: "首页",
},
children: [
{
path: "/home",
name: "home",
component: Home,
meta: {
title: "首页",
icon: "el-icon-s-home",
},
},
],
},
{
path: "*",
name: "404",
component: NotFound,
},
];
准备动态路由列表 (src/router/dynamicRouter.js)
const dynamicRouter = [{
path: '/resident',
name: 'resident',
component: () => import('@/views/resident/index.vue'),
meta: {
title: '用户管理',
icon: 'el-icon-user',
showMobile: true
},
children: [{
path: '/resident-list',
name: 'resident-list',
component: () => import('@/views/resident/resident.vue'),
meta: {
title: '用户列表',
showMobile: true
}
}
}
...
]
export default dynamicRouter
封装过滤函数 (src/utils/recursion-router.js)
/**
*
* @param {Array} userRouter 后台返回的用户权限json
* @param {Array} allRouter 前端配置好的所有动态路由的集合
* @return {Array} realRoutes 过滤后的路由
*/
export function recursionRouter(userRouter = [], allRouter = []) {
var realRoutes = allRouter
.filter(item => userRouter.includes(item.name))
.map(item => ({
...item,
children: item.children
? recursionRouter(userRouter, item.children)
: null
}))
return realRoutes
}
/**
*
* @param {Array} routes 用户过滤后的路由
*
* 递归为所有有子路由的路由设置第一个children.path为默认路由
*/
export function setDefaultRoute(routes) {
routes.forEach((v, i) => {
if (v.children && v.children.length > 0) {
v.redirect = { name: v.children[0].name }
setDefaultRoute(v.children)
}
})
}
权限设置(使用vuex管理)
import router, { DynamicRoutes } from "@/router";
import dynamicRoute from '@/router/dynamicRoute'
import { recursionRouter, setDefaultRoute } from '@/utils/recursion-router'
export default {
namespaced: true,
state: {
permissionList: null, /** 所有路由 */
sidebarMenu: [], /** 导航菜单 */
currentMenu: '', /** 当前active导航菜单 */
},
getters: {},
mutations: {
SET_PERMISSION(state, routes) {
state.permissionList = routes;
},
CLEAR_PERMISSION(state) {
state.permissionList = null;
},
SET_MENU(state, menu) {
state.sidebarMenu = menu;
},
CLEAR_MENU(state) {
state.sidebarMenu = [];
},
SET_CURRENT_MENU(state, currentMenu) {
state.currentMenu = currentMenu;
}
},
// 异步访问
actions: {
async FETCH_PERMISSION({ commit, state }) {
let permissions = ['testA', 'testB', 'testC', 'child_c_a', 'child_c_b']; // 接口获取,与路由名称 name 匹配
localStorage.setItem('permissions', permissions)
// 筛选
let routes = recursionRouter(permissions, dynamicRoute);
let MainContainer = DynamicRoutes.find(v => v.path === ''); // 找到path == ''的路由
let children = MainContainer.children;
children.push(...routes)
// 生成菜单
commit('SET_MENU', children);
// 设置默认路由
setDefaultRoute([MainContainer]);
// 初始化路由
let initialRoutes = router.options.routes;
DynamicRoutes.forEach(item => {
router.addRoute(item)
})
commit('SET_PERMISSION', [...initialRoutes, ...DynamicRoutes]);
}
}
}
路由守卫设置
import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
import ElementUI from "element-ui";
import "element-ui/lib/theme-chalk/index.css";
Vue.use(ElementUI);
Vue.config.productionTip = false;
/*
路由权限业务:
1. 定义全部路由地址
2. 通过登录不同用户向后台请求不同的权限数据
3. 对用户权限做对比: 请求数据 -对比- 全部路由
*/
router.beforeEach((to, from, next) => {
const token = localStorage.getItem("token");
if (!token) {
// 用户未登录
// 页面是否需要登录
if (
to.matched.length > 0 &&
!to.matched.some((record) => record.meta.requiresAuth)
) {
// 页面不需要登录
next();
} else {
// 需要登录
next({
path: "/login",
});
}
} else {
// 用户已登录 处理路由的访问权限
// 没有权限
if (!store.state.permission.permissionList) {
store.dispatch("permission/FETCH_PERMISSION").then(() => {
next({
path: to.path,
});
});
} else {
// store存在权限
if (to.path !== "/login") {
next();
} else {
next(from.fullPath);
}
}
}
});
router.afterEach((to, from, next) => {
var routerList = to.matched;
store.commit("setCrumbList", routerList);
store.commit("tags/setTags", to);
store.commit("permission/SET_CURRENT_MENU", to.path);
});
new Vue({
router,
store,
render: (h) => h(App),
}).$mount("#app");