vue如何根据权限生成动态路由、导航栏

作者:秋刀鱼笛滋味 时间:2024-05-05 09:25:43 

基本思路

1、创建vueRouter,用公共路由实例化

2、创建需要根据权限筛选的路由对象(在路由对象,添加必要的权限判断字段)

3、登录完成,由后端配合返回当前用户的权限集合

4、筛选出有权限的路由对象,利用vueRouter的addRoutes方法,生成完整路由

5、处理刷新页面导致vueRouter重新实例化导致路由对象不完善 (利用router.beforeEach导航守卫,,利用addRoutes()完善 路由对象 )

6、侧边导航栏相关代码

相关代码

根据上面的顺序

1、如下

Vue.use(Router)
// 公共路由
export const publicRoutes = [
 {
   path: '/',
   name: 'login',
   component: login,
   meta: {
     title: '登录'
   }
 }
]
// 需要根据权限筛选的路由
export const asyncRoutes = [
 ...Home,
 ...Seting,
 ...CRM,
 {
   path: '*',
   component: login,
   meta: {
     hidden: true
   },
   redirect: '/'
 }
]
const vr = new Router({
 mode: 'history',
 routes: publicRoutes
})

2、以seting模块为例,role为判断是的权限字段,角色有这个字段对应的值就有当前页面的权限

import Layout from '@/views/layout/layout.vue'
const account = r => require.ensure([], () => r(require('@/views/seting/account/account.vue')), 'seting');
const logs = r => require.ensure([], () => r(require('@/views/seting/logs/logs.vue')), 'seting');
const role = r => require.ensure([], () => r(require('@/views/seting/role/role.vue')), 'seting');
const Seting = [
 {
   path: '/seting',
   component: Layout,
   redirect: '/seting/account',
   meta: {
     title: '系统设置',
     role: '123c6c6514d416472e640bc3f49297c550',
     icon: 'icon-xitong'
   },
   children: [
     {
       path: 'account',
       name: 'account',
       component: account,
       meta: {
         title: '账号管理',
         role: '1325cdeb897cc7f8e951d647de9b1d8e11',
       }
     },
     {
       path: 'logs',
       name: 'logs',
       component: logs,
       meta: {
         title: '日志管理',
         role: '14bfbb0337ad3e7e2c9fc101294c3fe645',
       }
     },
     {
       path: 'role',
       name: 'role',
       component: role,
       meta: {
         title: '角色管理',
         role: '1559d1c05d15a0dce5549b8bf5a58c0cf9',
       }
     }
   ]
 }
]
export default Seting

如果有一些详情页不需要在导航列表展示还可以添加字段,在生成导航栏时去掉

eg:

{
           path: 'addJoiner',
           name: 'addJoiner',
           component: addJoiner,
           meta: {
             hidden: true,  // 隐藏字段
             title: '***详情页',
             role: '14bfbb0337ad3e7e2c9fc101294c3fe645',
           }
         },

3、登录获取权限集合和基本信息

// 登录
   login () {
     this.rememberPassword()
     this.$refs.form.validate((valid) => {
       if (valid) {
         this.loading = true
         let params = {
           login_name: this.form.user,
           password: this.form.password,
           code: this.form.yanzhenma,
         }
         this.$api.post('api/user/login', params).then(res => {
           if (res.err_code === 1) {
             // 把用户的基本信息储存在vuex,中
             this.$store.dispatch('setBaseInfo', res.data).then(() => {
               // 获取有权限的路由表,添加到路由
               router.addRoutes(this.$store.getters.addRouters)
               this.$router.push({ name: 'home' })
             })
           }
           this.loading = false
         })
       }
     })

部分vuex代码

如果不太理解,点击下面链接:

vuex刷新就没了解决方案

秒懂vuex

actions.js

// import api from '@/api'
const actions = {
 setBaseInfo ({
   commit
 }, data) {
   return new Promise(resolve => {
     commit('set_userInfo', data.userInfo)
     commit('set_token', data.token)
     commit('set_roles', data.menus)
     // 把基本信息保存在本地防止刷新之后丢失
     sessionStorage.setItem('baseInfo', JSON.stringify(data))
     resolve()
   })
 }
}
export default actions

mutations.js

const setStorage = (key, value) => {
 if (typeof (value) === 'object') {
   value = JSON.stringify(value)
 }
 sessionStorage.setItem(key, value)
}
/*
* 避免刷新之后vuex被重置,在sessionStorage做一个备份
*/
const mutations = {
 set_userInfo (state, payload) {
   state.userInfo = payload
   setStorage('userInfo', payload)
 },
 set_token (state, payload) {
   state.token = payload
   setStorage('token', payload)
 },
 set_roles (state, payload) {
   state.roles = payload
   setStorage('roles', payload)
 },
 set_breadcrumb (state, payload) {
   state.breadcrumb = payload
   setStorage('breadcrumb', payload)/*  */
 },
 changeCollapsed (state, payload) {
   state.isCollapsed = payload
 }
}
export default mutations

getters.js

import createdRoutes from '@/utils/createdRoutes.js'
import { asyncRoutes } from '@/router/index.js'
let getStoryage = (item) => {
 let str = sessionStorage.getItem(item)
 return JSON.parse(str)
}
const getters = {
 get_userInfo: (state) => {
   return state.userInfo ? state.userInfo : getStoryage('userInfo')
 },
 get_token: (state) => {
   return state.token ? state.token : sessionStorage.getItem('token')
 },
 get_roles: (state) => {
   return state.roles.length ? state.roles : getStoryage('roles')
 },
 addRouters: (state, getters) => {
   let routes = createdRoutes(asyncRoutes, getters.get_roles)
   return routes
 },
 get_breadcrumb: (state, getters) => {
   return state.breadcrumb.length ? state.breadcrumb : getStoryage('getStoryage')
 }
}
export default getters;

4、核心的筛选需要权限的路由方法:createdRoutes()

也就是3的getters,用到的方法,毫无保留奉上

/**
* 判单当前的路由对象是否在登录人的权限之内
* @param {Array} roles 权限
* @param {Object} route 路由
*/
function hasPermission (roles, route) {
 if (route.meta && route.meta.role) { // 路由需要权限就要在权限数组里面判断
   return roles.includes(route.meta.role)
 } else { // 不需要权限就直接通过
   return true
 }
}
/**
* 根据接口获取的权限列表动态生成当前用户的侧边导航栏,返回通过权限验证的路由数组
* @param {Array} asyncRoutes 需要过滤的路由
* @param {Array} roles 权限
*/
function createdRoutes (asyncRoutes, roles) {
 const accessedRouters = asyncRoutes.filter(route => {
   if (hasPermission(roles, route)) { // 当前路由通过权限验证直接通过
     if (route.children && route.children.length) { // 当前路由有子路由,就递归验证
       route.children = createdRoutes(route.children, roles)
     }
     return true
   }
   return false
 })
 return accessedRouters
}
export default createdRoutes

5、处理刷新带来的问题

其实这里的代码是连接1的,注意注释

// 全局的导航守卫
vr.beforeEach((to, from, next) => {
 // 刷新页面之后导致vue-router和vuex重置,路由丢失,利用的就是刷新后vuex的state被重置判断
 if (to.name !== 'login' && !store.state.token) {
   // 避免直接不登陆进页面
   if (!sessionStorage.getItem('token')) {
     location.href = '/'
     return
   }
   let data = JSON.parse(sessionStorage.getItem('baseInfo'))
   store.dispatch('setBaseInfo', data).then(() => {
     vr.addRoutes(store.getters.addRouters)
   })
 }
 // 设置面包屑导航
 let breadcrumb = to.matched.filter(item => item.meta.title)
 if (breadcrumb.length) {
   breadcrumb = breadcrumb.map(item => item.meta.title)
   store.commit('set_breadcrumb', breadcrumb)
 }
 // 设置title
 document.title = to.meta.title
 next()
})

6、侧边导航栏的完整代码

还是遍历的根据权限生成的路由表,干掉一些需要隐藏的详情页之类, 

这里的代码和过滤l路由的核心函数,要根据自己的业务做相应的处理

element-ui的menu

<template>
 <el-menu class="el-menu-vertical-demo" :collapse="isCollapsed" background-color="#545c64" :default-active='activeIndex' text-color="#fff" active-text-color="#7EA8F5">
   <section v-for="(item,index) in addRouters" :key="item.name" :class="isCollapsed ? 'collapsed':''">
     <!-- 有子菜单 -->
     <el-submenu :index=" `${index+1}`" v-if="!item.meta.hidden && item.children && item.children.length">
       <template slot="title">
         <i :class="`icon iconfont ${item.meta.icon}`"></i>
         <span slot="title">{{item.meta.title}}</span>
       </template>
       <section v-for="(item2,index2) in item.children" :key="item2.name">
         <!-- 二级菜单有子菜单 -->
         <el-submenu :index="`${index+1}-${index2+1}`" v-if="item2.children && item2.children.length" class="sub2">
           <template slot="title">
             <span slot="title">{{item2.meta.title}}</span>
           </template>
           <!-- * 菜单 -->
           <el-menu-item v-for="(item3,index3) in item2.children" v-if="!item3.meta.hidden" :index="item3.name" :key="index3" @click.native="$router.push({name:item3.name})">
             <span slot="title">{{item3.meta.title}}</span>
           </el-menu-item>
         </el-submenu>
         <!-- 二级菜单无子菜单 -->
         <!-- 不是隐藏的,详情页隐藏 -->
         <el-menu-item :index="item2.name" v-else-if="!item2.meta.hidden" @click.native="$router.push({name:item2.name})">
           <span slot="title">{{item2.meta.title}}</span>
         </el-menu-item>
       </section>
     </el-submenu>
     <!-- 无子菜单 -->
     <el-menu-item v-else-if="item.meta.hidden && item.children && item.children.length" :index="item.children[0].name" @click.native="$router.push({name:item.children[0].name})" class="item">
       <i :class="`iconfont ${item.children[0].meta.icon}`"></i>
       <span slot="title">{{item.children[0].meta.title}}</span>
     </el-menu-item>
   </section>
 </el-menu>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
 props: {
   isCollapsed: {
     type: Boolean,
     default: false
   }
 },
 computed: {
   ...mapGetters(['addRouters']),
   activeIndex () { //集火的菜单
     return this.$route.name
   }
 }
}
</script>

<style lang="scss" scoped>
section {
 /deep/ .el-submenu__title {
   .icon {
     margin-right: 10px;
   }
   i {
     color: white;
     font-size: 14px;
   }
 }
 /deep/ .el-menu-item {
   padding-left: 50px !important;
 }
 /deep/ .el-menu-item.item {
   padding-left: 19px !important;
   i {
     color: white;
     font-size: 14px;
     margin-right: 12px;
   }
 }
 /deep/ .el-submenu .el-menu-item {
   min-width: 0;
 }
 /deep/ .el-submenu.sub2 .el-submenu__title {
   padding-left: 50px !important;
   i {
     margin-right: 0px;
   }
 }
 /*   /deep/ .el-submenu.sub2 .el-menu-item {
   text-indent: 12px;
 } */
}
.collapsed {
 width: 50px;
 /deep/ .el-submenu__title {
   .el-icon-arrow-right {
     display: none;
   }
   span[slot="title"] {
     display: none;
   }
 }
}
</style>

路由图

vue如何根据权限生成动态路由、导航栏

以上为个人经验,希望能给大家一个参考,也希望大家多多支持asp之家。 

来源:https://blog.csdn.net/weixin_43206949/article/details/89352424

标签:vue,权限,路由,导航栏
0
投稿

猜你喜欢

  • 基于Python实现拆分和合并GIF动态图

    2021-09-09 18:05:57
  • Golang多线程排序实现快速高效地处理大规模数据

    2024-04-27 15:32:29
  • Django3.2 自动发现所有路由代码详解

    2022-08-10 21:35:14
  • 如何使用共享连接减少空闲的连接数?

    2010-05-16 15:15:00
  • ASP处理XSLT转换XML的实现

    2008-10-20 18:37:00
  • javascript双击自动滚屏单击停止

    2008-10-13 13:05:00
  • MySQL触发器简单用法示例

    2024-01-26 11:26:53
  • 简单的自定义php模板引擎

    2023-11-24 02:44:24
  • PyTorch数据读取的实现示例

    2022-01-31 04:15:48
  • pandas学习之df.fillna的具体使用

    2023-10-16 20:34:08
  • 教你四种方法用来查看mysql版本

    2009-06-28 11:13:00
  • ASP实现网站智能分词搜索

    2007-10-18 13:50:00
  • mysql外键基本功能与用法详解

    2024-01-23 00:52:13
  • 在pycharm中debug 实时查看数据操作(交互式)

    2023-01-19 08:31:11
  • Python及Django框架生成二维码的方法分析

    2023-10-11 22:25:48
  • MySQL批量插入数据脚本

    2024-01-16 13:31:14
  • python导包的几种方法(自定义包的生成以及导入详解)

    2021-11-19 21:33:41
  • 分享五个超实用Python脚本,减少垃圾软件负担

    2022-07-18 18:38:59
  • Go单体服务开发最佳实践总结

    2024-04-26 17:35:48
  • Python对XML文件实现增删改查操作

    2023-11-19 20:42:03
  • asp之家 网络编程 m.aspxhome.com