Vue 权限菜单及按钮权限
一.服务端数据
Vue 权限菜单需要根据后端返回的数据来实现
[
{pid:-1,name:'购物车',id:1,auth:'cart'},
{pid:1,name:'购物车列表',id:4,auth:'cart-list'},
{pid:4,name:'彩票',id:5,auth:'lottery'},
{pid:4,name:'商品',id:6,auth:'product'},
{pid:-1,name:'商店',id:2,auth:'shop'},
{pid:-1,name:'个人中心',id:3,auth:'store'},
];
通过 express 返回权限列表
const express = require('express');
const app = express();
app.all('_', (req, res, next) => {
res.header('Access-Control-Allow-Origin', '_');
// Access-Control-Allow-Headers ,可根据浏览器的 F12 查看,把对应的粘贴在这里就行
res.header('Access-Control-Allow-Headers', 'Content-Type');
res.header('Access-Control-Allow-Methods', '\*');
res.header('Content-Type', 'application/json;charset=utf-8');
next();
});
app.get('/roleAuth', (req, res) => {
res.json({
menuList: [
{pid:-1,name:'购物车',id:1,auth:'cart'},
{pid:1,name:'购物车列表',id:4,auth:'cart-list'},
{pid:4,name:'彩票',id:5,auth:'lottery'},
{pid:4,name:'商品',id:6,auth:'product'},
{pid:-1,name:'商店',id:2,auth:'shop'},
{pid:-1,name:'个人中心',id:3,auth:'store'},
]
});
});
app.listen(3000);
二.静态菜单
使用 element-ui 构建静态菜单
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
<el-menu default-active="2" class="el-menu-vertical-demo">
<el-submenu index="1">
<template slot="title">导航一</template>
<el-submenu index="1-1">
<template slot="title">选项 1-1</template>
<el-menu-item index="1-1-1">选项 1-1-1</el-menu-item>
<el-menu-item index="1-1-2">选项 1-1-2</el-menu-item>
</el-submenu>
<el-menu-item index="1-2">选项 1-2</el-menu-item>
</el-submenu>
<el-menu-item index="2">
导航二
</el-menu-item>
<el-menu-item index="3">
导航三
</el-menu-item>
<el-menu-item index="4">
导航四
</el-menu-item>
</el-menu>
路由配置
import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'
Vue.use(Router)
export const authRoutes = [ // 权限路由
{
path: '/cart',
name: 'cart',
component: () => import('@/views/Cart'),
children: [
{
path: 'cart-list',
name: 'cart-list',
component: () => import('@/views/CartList'),
children: [
{
path: 'lottery',
name: 'lottery',
component: () => import('@/views/Lottery'),
},
{
path: 'product',
name: 'product',
component: () => import('@/views/Product'),
},
],
},
],
},
];
export default new Router({ // 默认导出 首页和 404 页面
mode: 'history',
base: process.env.BASE_URL,
routes: [
{
path: '/',
name: 'home',
component: Home
},
{
path:'*',
component:{
render:h=>h('h1',{},'Not Found')
}
}
]
})
三.获取权限
根据后端返回的数据,格式化树结构,并提取用户权限
// 默认设置没有获取过权限
export default new Vuex.Store({
state: {
hasPermission:false
},
mutations: {
setPermission(state){
state.hasPermission = true
}
},
})
在路由跳转前看下是否获取过权限,如果没有获取过,就获取权限存入 vuex 中
router.beforeEach(async (to,from,next)=>{
if(!store.state.hasPermission){
// 获取最新路由列表
let newRoutes = await store.dispatch('getRouteList');
router.addRoutes(newRoutes); // 增加新路由
next({...to,replace:true})
}else{
next(); // 获取过就不需要再次获取了
}
})
四.获取相关需要数据
const getMenListAndAuth = (menuList)=>{
let menu = [];
let sourceMap = {};
let auth = [];
menuList.forEach(m => {
m.children = []; // 增加孩子列表
sourceMap[m.id] = m;
auth.push(m.auth)
if(m.pid === -1){
menu.push(m); // 根节点
}else{
sourceMap[m.pid] && sourceMap[m.pid].children.push(m)
}
});
return {menu,auth} // 获取菜单数据和权限数据
}
async getRouteList({dispatch,commit}){
let auths = await axios.get('http://localhost:3000/roleAuth');
let menuList = auths.data.menuList;
let {menu,auth} = getMenListAndAuth(menuList);
}
五.找到需要添加的路由
import {authRoutes} from './router'
const getRoutes = auth => {
const filter = (authRoutes)=>{
return authRoutes.filter(route=>{
// 包含权限
if(auth.includes(route.name)){
if(route.children){
route.children = filter(route.children);
}
return true;
}
})
}
return filter(authRoutes);
};
// 获取需要添加的路由列表
async getRouteList({ dispatch, commit }) {
let auths = await axios.get("http://localhost:3000/roleAuth");
let menuList = auths.data.menuList;
let { menu, auth } = getMenListAndAuth(menuList);
commit("setMenu", menu); // 将菜单数据保存起来
commit("setPermission"); // 权限获取完毕
// 通过 auth 查找需要添加的路由
return getRoutes(auth);
}
六.递归渲染菜单
渲染 Menu 组件提取公共部分
<template>
<div>
<el-menu>
<template v-for="menu in $store.state.menu">
<el-submenu v-if="menu.children.length" :key="menu.auth" :index="menu.auth">
<template slot="title">{{menu.name}}</template>
<!-- 此处需要不停的递归 el-submenu -->
</el-submenu>
<el-menu-item v-else :key="menu.auth" :index="menu.auth">{{menu.name}}</el-menu-item>
</template>
</el-menu>
</div>
</template>
编写递归组件
<template>
<el-submenu :index="menu.auth">
<template slot="title">{{menu.name}}</template>
<template v-for="(child,index) in menu.children">
<el-menu-item v-if="!child.children.length" :key="index">
<router-link :to="{name:child.auth}"> {{child.name}}</router-link>
</el-menu-item>
<!-- 如果有儿子继续递归组件 -->
<ResubMenu :menu="child" v-else :key="index"></ResubMenu>
</template>
</el-submenu>
</template>
<script>
export default {
name:'ResubMenu',
props:{
menu:{}
}
}
</script>
七.权限按钮控制
state: {
hasPermission: false,
menu: [], // 菜单权限
btnPermission:{ // 按钮权限
edit:false,
add:true
}
},
查看当前按钮是否有权限
<el-button v-has="'edit'">编辑</el-button>
<el-button v-has="'add'">添加</el-button>
自定义指令的使用
directives: {
has: {
inserted(el, bindings, vnode) {
let value = bindings.value;
// 在 vuex 中查看是否有按钮权限
let flag = vnode.context.\$store.state.btnPermission[value];
// 如果没有全选则将按钮删除即可
!flag && el.parentNode.removeChild(el);
}
}
}
10 声望
1 粉丝
推荐阅读
内置对象string的方法
在js中,String和Array是同级的,都是js中的内置对象。因此String也像Array那样有很多操作的方法。注意:String对象的涵盖范围,它包含所有的字符串。1. 字符串对象的属性length(1) 表示字符串的长度。(就是这个...
王影阅读 901
ESlint + Stylelint + VSCode自动格式化代码(2023)
安装插件 ESLint,然后 File -> Preference-> Settings(如果装了中文插件包应该是 文件 -> 选项 -> 设置),搜索 eslint,点击 Edit in setting.json
谭光志赞 34阅读 20.7k评论 9
vue UI框架比较
最好基于vue2.0PC端:因为用过的是饿了么UI,所以比较以饿了么UI为基础element UI 饿了么UI支持vue2.x80分优点:组件的API方法、属性等封装的较为完善缺点:样式有些生硬,不够炫酷美观N3 N3支持vue2.x70分优点:...
chinawzc赞 22阅读 39.8k评论 17
【已结束】SegmentFault 思否写作挑战赛!
SegmentFault 思否写作挑战赛 是思否社区新上线的系列社区活动在 2 月 8 日 正式面向社区所有用户开启;挑战赛中包含多个可供作者选择的热门技术方向,根据挑战难度分为多个等级,快来参与挑战,向更好的自己前进!
SegmentFault思否赞 20阅读 5.6k评论 10
Vue2 导出excel
2020-07-15更新 excel导出安装 {代码...} src文件夹下新建一个libs文件夹,新建一个excel.js {代码...} vue页面中使用 {代码...} ===========================以下为早期的文章今天在开发的过程中需要做一个Vue的...
原谅我一生不羁放歌搞文艺赞 14阅读 20k评论 9
用了那么久的 SVG,你还没有入门吗?
其实在大部分的项目中都有 直接 或 间接 使用到 SVG 和 Canvas,但是在大多数时候我们只是选择 简单了解 或 直接跳过,这有问题吗?没有问题,毕竟砖还是要搬的!
熊的猫赞 17阅读 1.6k评论 2
嘿,vue中keep-alive有个「大坑」你可能还不知道
背景是这样的,我们使用vue2开发一个在线客服使用的IM应用,基本布局是左边是访客列表,右边是访客对话,为了让对话加载更友好,我们将对话的路由使用<keep-alive>缓存起来。但是如果将所有对话都缓存,未...
wuwhs赞 12阅读 2.6k
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。