引言
看了很多关于后台管理访问权限的代码和实现原理,有的是放在meta里的可访问的用户,有的是返回的 routerConfig 。主要还是看后端的实现程度。
然后自己做了一个 通过 addRouters 添加 routerConfig 来实现对路由的动态添加。
本次实现
- 前端 可视化页面及按钮配置权限
- 后端 处理 返回处理好路由数据
- 前端当前登录用户
- 后端根据登录用户返回对应的 routerConfig
路由守卫 和 动态添加路由
路由守卫 就是当前端页面的url每发生页面跳转时都会先触发 路由守卫 然后由 路由守卫 决定,是否跳到下个页面。
动态添加路由 添加用户可以跳转的路由页面路径。
实现效果图
github地址 https://github.com/liuguangqing/addRouter-for-limits
技术 : vue-cli3 + mockJs + ts + vue-router + vuex-class + element-ui + axios + addRouter
mockjs 本地模拟了用户权限接口返回,下载之后可以直接运行看到效果
用户登录页面
登录用户:front
登录用户:admin
router Api
代码实现
1、components.ts 本地保存的路由地址
// components.ts 本地保存的路由地址
const routeMap: any = {
index: () => import('../views/index.vue'),
home: () => import('../views/home.vue'),
about: () => import('../views/about.vue'),
zhaoxin: () => import('../views/zhaoxin.vue'),
change: () => import('../views/change.vue'),
addAdverse: () => import('../views/addAdverse.vue')
};
export { routeMap }
2、router.ts Config (主要部分)
// router.ts 路由 config
import Vue from "vue";
import VueRouter from "vue-router";
import ax from '@/service/axios';
import routes from './comonRouters';
import { formatRoutes } from './utils';
import { Message } from 'element-ui'
Vue.use(VueRouter);
const router = new VueRouter({
mode: "history",
routes
});
const NotFound = () => import('@/views/layout/404.vue');
router.beforeEach((to: any, from: any, next: any) => {
let storeJs: any = router.app.$options.store
const username = sessionStorage.getItem('username');
if(!username && to.path !== '/login'){
Message.error('请先登录当前用户');
next({path: '/login'});
} else if (storeJs.state.remoteRouteRefresh && to.path !== '/login') {
ax({url: '/login', method: 'post', data: {token: storeJs.state.token}}).then((res: any) => {
console.warn('模拟请求-成功', res)
if (res.status === 200 && res.data.errno === 0) {
const menuData = res.data.result;
storeJs.commit('set_remoteRouteRefresh', false)
storeJs.commit('set_menudata', menuData)
localStorage.setItem('menudata', JSON.stringify(menuData));
const routeData = formatRoutes(menuData);
router.addRoutes([routeData].concat([
{name:'404',path:'/404',component: NotFound},
{path:'*',redirect: '/404'}
]));
Message.success('恭喜登录成功。。');
next(to.path)
}
else {
storeJs.commit('set_remoteRouteRefresh', true)
Message.error('不存在此用户 !');
next({path: '/login'});
}
})
.catch((err: any) => {
console.log(err);
});
} else {
next();
}
})
export default router;
3、utils.ts 更改后端返回的数据为路由所需要的数据
// utils.ts
import { routeMap } from './components';
interface asd {
component?: any,
path?: any,
name?: any,
index?: any,
title?: any,
children?: any
}
const formatRoutes = function (routes: any, routeData?: any) {
routes.length && routes.forEach((route: asd) => {
if (!routeData) {
routeData = {
path: route.path,
name: route.name,
// 组件匹配成功的话才可以访问具体的页面
component: routeMap[route.component],
children: [],
};
}
if (route.component && routeData) {
route.component = routeMap[route.component];
routeData.children.push({
path: route.path,
name: route.name,
component: route.component,
meta: {
title: route.title,
},
})
}
if (route.children && route.children.length) {
formatRoutes(route.children, routeData);
}
});
return routeData;
};
export { formatRoutes }
4、comonRouters.ts 公共路由 不需要用户权限的配置
// comonRouters.ts 公共路由配置
import login from "@/views/layout/login.vue";
const routes: any[] = [
{
path: "/",
redirect: '/home/index'
},
{
path: "/login",
component: login
}
];
export default routes
5、mock.ts 模拟接口返回数据
// 指定当前只有 front 和 admin 用户
import Mock from 'mockjs';
function loginFun(prarms: any) {
const prarmsObj = JSON.parse(prarms.body);
let sendObj = {
"errno": 0,
"errmsg": "获取权限成功",
"result": [
{
"path": "/home",
"name": "首页",
"component": "home",
"children": [
{
"path": "/home/index",
"name": "首页",
"component": "index",
"isShow": true
}
]
}
]
}
if (prarmsObj.token == 'front') {
sendObj.result[0].children.push(
{
"path": "/home/addAdverse",
"name": "地址",
"component": "addAdverse",
"isShow": true
},
{
"path": "/home/change",
"name": "嫦娥",
"component": "change",
"isShow": true
}
)
} else if (prarmsObj.token == 'admin') {
sendObj.result[0].children.push(
{
"path": "/home/about",
"name": "关于",
"component": "about",
"isShow": true
},
{
"path": "/home/zhaoxin",
"name": "赵信",
"component": "zhaoxin",
"isShow": true
}
)
} else {
sendObj.errno = 1
sendObj.errmsg = '没有此用户'
}
return sendObj
}
Mock.mock('/api/login', 'post', loginFun); //登录
6、home.vue 路由菜单
<el-aside width="200px">
<el-menu
:router="true"
default-active="2"
class="el-menu-vertical-demo"
@open="handleOpen"
@close="handleClose"
background-color="#545c64"
text-color="#fff"
active-text-color="#ffd04b">
<template v-for="(ite, ind) in menudata">
<el-submenu index="1" v-if='ite.children && ite.children.length > 0' :key="ind">
<template slot="title">
<i class="el-icon-location"></i>
<span>{{ite.name}}</span>
</template>
<el-menu-item-group>
<el-menu-item :index="ite2.path" v-for="(ite2, ind2) in ite.children" :key="ind2">{{ite2.name}}</el-menu-item>
</el-menu-item-group>
</el-submenu>
<el-menu-item :index="ite.path" v-else :key="ind">
<i class="el-icon-menu"></i>
<span slot="title">{{{{ite.name}}}}</span>
</el-menu-item>
</template>
</el-menu>
</el-aside>
本地储存菜单的数据只是作为其他用途,看大家需要, 没有必要本地存的话也可以只存在vuex中 ,而且如果用户通过控制台修改了 menuData, 如果用户 F5 刷新了页面,直接去获取一次就行了。
本文出自 香菊网 xiangjv.top
思路借鉴 全能的阿豪:vue实现菜单权限控制
标签: js部分前端frontH5部分