实现思路:

1.通过利用动态路由、静态路由实现动态路由

2.通过router-beforeEach钩子监听是否有权限

3.利用Vue.directive监听页面挂在完成控制按钮权限

实现代码:

route.js

router文件下有两个文件,1个是用来存储静态路由(登录页)、动态路由,另一个文件则是用于监听路由钩子

/*** @description 默认路由
*/
export const constantRouterMap = [{path: '/',redirect: '/login',hidden: true},{path: '/login',name: 'login',hidden: true,component: () => import('../views/login/index.vue')}
]
/*** @description 动态路由
*/
export const asyncRouterMap = [{path:'/home',name:'home',meta: {title: '首页',icon:'' // 用于显示左侧菜单icon},component () => import(../views/Home/index.vue) //动态导入组件
},
{path:'/dosc',name:'Dosc',redirect:'/dosc/dosclist' //重定向meta: {title: '文件管理',icon:'' // 用于显示左侧菜单icon},component: () => import(../views/layout/index.vue) //默认入口组件children:[{path:'/dosc/dosclist',name:'doscList',meta:{name:'文件列表',breadcurmbName:'文件列表'},component:() => import(../view/dosc/dosclist/index.vue),children:[{hidden: true,path: '/dosc/detail/:id',name: 'doscDetail',meta: {breadcrumbName: '文件详情'},component: () => import('../views/dosclist/detail.vue')}]},{path:'/dosc/storelist',name:'storeList',meta:{name:'存储列表',breadcurmbName:'存储列表'},component:() => import(../view/dosc/store/index.vue)}]
}
]

index.js

页面刷新时,vuex会被清空所以需要从localStorage中重新获取路由及按钮权限。需要判断token是否过期,过期需要重新登录。

import { createRouter, createWebHistory } from 'vue-router'
import { constantRouterMap } from './route'
import store from '../store'
import { getToken} from '../utils/cook'
const router = createRouter({history: createWebHistory(process.env.BASE_URL),routes:constantRouterMap
})
router.beforeEach((to,from) => {
try{const menu = localStorage.getItem("menus") !== null ?JSON.parse(window.decodeURIComponent(window.atob(localStorage.getItem("menus")))) : [] const buttons = localStorage.getItem("buttons") !== null ? JSON.parse(window.decodeURIComponent(window.atob(localStorage.getItem("buttons")))) : []if (to.path === '/login') {if (!getToken()) {localStorage.clear()return true}return router.push('/default')}if (!getToken()) {localStorage.clear()return router.push('/login')}
if (store.getters.addRouters.length === 0) {if(menus.length > 0){store.dispatch('GenerateRoutes', { menus }).then(() => {// 动态添加可访问路由表addAsyncRoute(store.getters.addRouters)/*** @description 更新按钮权限*/store.dispatch('UpdateHasButtons',buttons)return router.push(to.path)})}else{store.dispatch('GetInfo').then(res => { // 拉取用户信息let {menus,buttons} = res
localStorage.setItem('menus',window.btoa(window.encodeURIComponent(JSON.stringify(menus))))         localStorage.setItem('buttons',window.btoa(window.encodeURIComponent(JSON.stringify(buttons))))store.dispatch('UpdateHasButtons',buttons)store.dispatch('GenerateRoutes', { menus }).then(() => { // 生成可访问的路由表addAsyncRoute(store.getters.addRouters); // 动态添加可访问路由表return router.push(to.path)})}).catch((err) => {store.dispatch('ClearUserInfo')return router.push('/login')})/*** @description 更新按钮权限*/store.dispatch('getButtons')}
}else{return true
}
}
catch{
localStorage.clear()
router.push('/login')}
})
function addAsyncRoute(routers){for(let i= 0 ;i < routers.length;i++){const routeItem = Object.assign({},routers[i])router.addRoute(routeItem)}
}

利用vuex存储路由及按钮

store文件夹下有modules模块文件夹(permession.js、user.js)、getters获取store文件

permession.js

用来存储路由权限、按钮权限。

import { asyncRouterMap, constantRouterMap } from '@/router/route';
import store from '../../store'
//判断是否有权限访问该菜单
function hasPermission(menus, route,parent) {if (route.name) {let currMenu = getMenu(route.name, menus);if (currMenu!=null) {return true;} else {if (route.hidden !== undefined && route.hidden === true) {return true;} else {return false;}}} else {return true}
}
//根据路由名称获取菜单
function getMenu(name, menus) {console.log('name',name);let targetMenu = {}for (let i = 0; i < menus.length; i++) {let menu = menus[i];if (menu.name === name) {return menu;}/*** @description 返回嵌套菜单权限*/if(menu.children && menu.children.length > 0){targetMenu = getMenu(name,menu.children)if(targetMenu !== undefined) return targetMenu}}// return null;
}
/*** @description 多层深度拷贝
*/
function deepCopy(params) {// 如果是数组if (Array.isArray(params)) {var res = [];for (var i = 0; i < params.length; i++) {if (params[i] instanceof Object) {// 将深层拷贝的结果的 添加到 res 中res.push(deepCopy(params[i]));} else {res.push(params[i]);}}return res;}// 如果是对象 进行 对象的拷贝if (params.constructor === Object) {var res = {}; //  1 声明空对象for (var x in params) {// 遍历被拷贝独享// 如果你是数组或者对象;需要再次拷贝if (params[x] instanceof Object && !params[x] instanceof Function) {// 将深层拷贝的结添加到 res中res[x] = deepCopy(params[x]);} else {// params[x] 为基本类型数据 直接添加大res中res[x] = params[x];}}return res}
}
const app = {state: () => ({routers: constantRouterMap,addRouters: [],hasButtons:[]}),mutations: {SET_ROUTERS: (state, routers) => {state.addRouters = routers;routers.push({path: '/:pathMatch(.*)*',name: 'error',hidden: true,component: () => import('../../views/error/404/index.vue')})if(routers[0].children && routers[0].children.length > 0){const path =routers[0].children[0].pathrouters[0].children[0].path = '/default'routers[0].children[0].alias = path}else{const path =routers[0].pathrouters[0].path = '/default'routers[0].alias = path}state.routers = constantRouterMap.concat(routers);},UPDATE_ROUTERS:(state,routers) =>{state.routers = routers},UPDATE_HASBUTTONS:(state,buttons) =>{state.hasButtons = buttons},CLEAR_ROUTES:(state) =>{state.routers = constantRouterMapstate.addRouters = []}},actions: {GenerateRoutes({ commit }, data) {return new Promise(resolve => {const { menus } = data;const primaryAsync = deepCopy(asyncRouterMap)  const accessedRouters = primaryAsync.filter(v => {if (hasPermission(menus, v)) {if (v.children && v.children.length > 0) {v.children = v.children.filter(child => {if (hasPermission(menus, child,v)) {   if(child.children && child.children.length > 0){  child.children = child.children.filter(ren => {if(hasPermission(menus,ren,child)){return ren}return false})return child}else{return child}}return false;});return v} else {return v}}return false;});commit('SET_ROUTERS', accessedRouters);resolve();})},UpdateRoutes({commit},routers){commit('UPDATE_ROUTERS',routers)},UpdateHasButtons({commit},buttons){commit('UPDATE_HASBUTTONS',buttons)},ClearRoutes({commit}){commit('CLEAR_ROUTES')}}
};

user.js

用来存储用户权限。

import ajax from '@/api/account'
const app = {state: () => ({userInfo: {username: localStorage.getItem('username') || '',name: localStorage.getItem('name') || '',role: localStorage.getItem('role') || ''}}),mutations: {CLEAR_USERINFO: (state) => {state.userInfo = {username: '',name: '',role: ''}},UPDATE_USERINFO: (state, userInfo) => {state.userInfo = {...state.userInfo,...userInfo}}},actions: {ClearUserInfo ({commit}) {commit('CLEAR_USERINFO')},UpdateUserInfo ({commit}, userInfo) {commit('UPDATE_USERINFO', userInfo)},// 获取用户信息GetInfo({ commit}) {return new Promise((resolve, reject) => {ajax.getInfo().then(response => {resolve(response)}).catch(error => {reject(error)})})},}
}export default app

getters.js

用来获取store中的存储信息。

const getters = {userInfo: (state) => state.user.userInfo,addRouters: (state) => state.permission.addRouters,routers: (state) => state.permission.routers,hasButtons:(state) => state.permission.hasButtons
}export default getters

按钮权限检验

挂载完成时通过用户名称去判断该用户是否拥有该按钮,来控制按钮的显示、隐藏。

import store  from "../store"
export default (Vue) => {/**自定义按钮权限指令 */Vue.directive('has', {mounted(el, binding) {//获取按钮权限if (!Vue.config.globalProperties.$_has(binding.value)) {//移除不匹配的按钮el.parentNode.removeChild(el)}},})//检查权限方法Vue.config.globalProperties.$_has = function (value) {let isExist = falseconst btnPermsArr = store.getters.hasButtonsif (btnPermsArr.includes(value)) {isExist = true}console.log('isExist',isExist);return isExist}
}

登录时根据接口返回动态判断用户的路由、按钮,并同时存入vuex、locastorage

login(value).then(res => {if (res) {clearStorage()setToken(res.access)this.$store.dispatch('UpdateUserInfo', {username: res.username,name: res.name,role: res.role})this.$store.dispatch('GetInfo').then(res => {let {menus,buttons} = reslocalStorage.setItem('menus',window.btoa(window.encodeURIComponent(JSON.stringify(menus))))localStorage.setItem('buttons',window.btoa(window.encodeURIComponent(JSON.stringify(buttons))))this.$store.dispatch('UpdateHasButtons',buttons)this.$store.dispatch('GenerateRoutes', { menus }).then(() => { // 生成可访问的路由表this.addAsyncRoute(this.$store.getters.addRouters)this.$router.push('/default')})}).catch((err) => {clearStorage()return this.$router.push('/login')})}}).catch(() => {})

菜单权限及按钮权限控制相关推荐

  1. vue项目权限:数据权限、菜单权限、按钮权限

    前言 不管是移动端,还是pc端,可能都会有用户登录操作,不同的用户之间又拥有不同的角色,而不同角色之间势必存在不同的权限: 如果按照类型划分,大概可分为三类:菜单权限.按钮权限.数据权限: 数据权限: ...

  2. 管理台权限模块 - 完整路由权限及按钮权限

    这篇文章主要讲的是动态路由添加,下篇我们再仔细说明一下按钮权限的做法, 本文基础框架在element-ui 及element-admin-template基础上进行的二次开发 动态路由权限: 首先这里 ...

  3. 前端动态菜单权限、按钮权限实现思路

  4. Vue 前端页面按钮权限控制

    前言 按钮权限控制的功能其实在前面的一篇的页面权限管理也包含有这个功能,但是没有凸显出来,所以现在单独写一篇文章用来记录一下 一.什么是按钮权限控制? 刚刚做完了一个后台管理系统,有用到按钮权限控制, ...

  5. php前端路由权限,SaaS-前端权限控制

    1 前端权限控制 1.1 需求分析 1.1.1 需求说明 基于前后端分离的开发模式中,权限控制分为前端页面可见性权限与后端API接口可访问行权限.前端的权限控制主要围绕在菜单是否可见,以及菜单中按钮是 ...

  6. 权限系统 6_1权限管理

    硅谷通用权限系统:权限管理 一.权限管理 1.权限管理介绍 每个系统的权限功能都不尽相同,各有其自身的业务特点,对权限管理的设计也都各有特色.不过不管是怎样的权限设计,大致可归为三种:页面权限(菜单级 ...

  7. netcore权限控制_netcore mvc快速开发系统(菜单,角色,权限[精确到按钮])开源...

    基于netcore2.0 mvc 开发的 快速搭建具有如下特色的后台管理系统 特色: 用户管理 菜单管理 角色管理 权限管理[精确到按钮]) 代码生成器 如何使用 代码克隆到本地 用vs2017或以上 ...

  8. netcore mvc快速开发系统(菜单,角色,权限[精确到按钮])开源

    基于netcore2.0 mvc 开发的 快速搭建具有如下特色的后台管理系统 用户管理 菜单管理 角色管理 权限管理[精确到按钮]) 代码生成器 代码克隆到本地 用vs2017或以上版本 打开工程. ...

  9. AppBoxPro - 细粒度通用权限管理框架(可控制表格行内按钮)源码提供下载

    2019独角兽企业重金招聘Python工程师标准>>> 特别声明: 提供的源代码已经包含了 AppBoxPro 的全部源代码,用 VS2012 打开项目后,直接 Ctrl+F5 可以 ...

最新文章

  1. HSmartWindowControl 之 摄像头实时显示( 使用 WPF )
  2. docker mysql编辑器_docker官方mysql镜像自定义配置详解
  3. 【详细注解】1020 Tree Traversals (25 分)
  4. du -sh 如何找到最大的文件夹_小白必看!手把手教你如何在linux上安装redis数据库...
  5. python爬虫知乎图片_python爬虫(爬取知乎答案图片)
  6. 在IntelliJ IDEA里配置Go开发环境
  7. Python批量导入图片生成PowerPoint 2007+文件
  8. lodash是否是数组_lodash源码解析:for家族
  9. 综述 | 跨语言自然语言处理论文汇总
  10. Glide4.0源码全解析(二),load()背后的故事
  11. VS C++ 从字符串中查找字符最后一次出现的位置 strrchr
  12. ASCII对应码表(键值)
  13. 数据挖掘的9大成熟技术和应用
  14. 2018年世界计算机超算大赛,2018ASC世界大学生超算竞赛开赛:11队齐破赛会纪录...
  15. 八股文之linux常用指令
  16. ubuntu命令行查看dns_linux命令,查看dns服务器的状态,查看dhcp服务器的状态
  17. H5实现扫一扫(二)
  18. 蕾辈使匚冉吃勘刚莱涨坟怪
  19. 高性能Javascript(1)
  20. [JZOJ6355] 【NOIP2019模拟】普 24/100

热门文章

  1. 第十六章、文件服务器之二: SAMBA 服务器
  2. PX4程序编译过程解析
  3. 选择短信平台加快提升医院部门信息化管理
  4. try catch使用
  5. html怎么把一段文字设置为连接到下一个网页的按钮,为主页添加一个漂亮的按钮(上)_html...
  6. 星际争霸AI训练环境与自主规划决策问题初探
  7. 开源EDR(OSSEC)基础篇- 01 -设计定位与能力输出
  8. JSP标签,JSTL标签,EL标签
  9. ArcGIS实现从左到右从下而上顺序自动编号方法
  10. 【中级软件设计师】—(摆烂记点单词)计算机专业英语单词总结(四十三)