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

目录
  • 基本思路
  • 相关代码

基本思路

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>

路由图

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

(0)

相关推荐

  • vue实现动态路由详细

    目录 一.前端控制 1.在router.js文件(把静态路由和动态路由分别写在router.js) 2.store/permission.js(在vuex维护一个state,通过配角色来控制菜单显不显示) 3.src/permission.js 4.侧边栏的可以从vuex里面取数据来进行渲染 二.后端控制路由 1.store/permission.js,在vuex里面发送请求获取数据 2.整理一份数据结构,存到表里 3.写一个转化方法,把获取到的数据转换成router结构 主流的实现方式: 简单

  • vue 实现动态路由的方法

    很多时候我们在项目的路由都是在前端配置好的 但是有的时候为了进行全面的权限控制,会需要后台给出路由表,前端再渲染.不用在前端配置. 下面主要讲一下思路 1.和后台小哥哥沟通好数据,把我们前端配置的路由表数据给他,他就能看懂了 2.拿到数据需要我们自己再处理 路由中的component后台是给不了的,这里我们只需要后台小哥哥按照我们提供的前端component路径给数据,我们循环加载就可以了 //view就是后台给的数据 return () => import(`@/view/modules/${

  • vue-router 基于后端permissions动态生成导航菜单的示例代码

    目录 Vue.js 1.注册全局守卫 2.Vuex状态管理 全局缓存routes 3.路由拦截 4.路由菜单 5.递归菜单vue组件 Vue.js vue-router vuex 1.注册全局守卫 核心逻辑 1.token身份验证(后端) => token失效返回登录页面 2.获取用户权限 3.校验permissions,动态添加路由菜单 router.beforeResolve 注册一个全局守卫.和 router.beforeEach 类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路

  • vue addRoutes实现动态权限路由菜单的示例

    需求 最近接手一个后台管理系统,需要实现导航菜单从后台拉取的效果:根据登录用户的权限不同分别拉出来的导航菜单也不一样,另外可操作的界面也存在区别. 问题 因为后台管理系统是准备使用vue+vue-router+element-ui+vuex的搭配来做的,可是单页应用在进入页面之前就已经将vue-router实例化并且注入vue实例中了,所以在进入登录页面的时候旧没办法在重新定制路由了.接下来各种百之谷之,发现vue-router在2.0版本中提供了addRoutes方法添加路由,希望的曙光出现.

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

    目录 基本思路 相关代码 基本思路 1.创建vueRouter,用公共路由实例化 2.创建需要根据权限筛选的路由对象(在路由对象,添加必要的权限判断字段) 3.登录完成,由后端配合返回当前用户的权限集合 4.筛选出有权限的路由对象,利用vueRouter的addRoutes方法,生成完整路由 5.处理刷新页面导致vueRouter重新实例化导致路由对象不完善 (利用router.beforeEach导航守卫,,利用addRoutes()完善 路由对象 ) 6.侧边导航栏相关代码 相关代码 根据上

  • vue后台管理如何配置动态路由菜单

    目录 后台管理配置动态路由菜单 根据权限生成动态路由及导航菜单 后台管理配置动态路由菜单 前段时间做一个后台管理项目,因为超级管理员可以给普通管理员动态更改权限,所以vue-element-admin里的写死的权限路由菜单就不太适合我,自己研究了好半天,经历了各种死循环,终于差不多弄出了一个,可能会有点啰嗦,总结一下: 我这个后台分为三个角色:超级管理员.企业管理员和普通管理员.其中,超级管理员可以查看所有的路由菜单,企业管理员也是固定的几个菜单,所以,超级管理员和企业管理员是我在前端写好的路由

  • Vue实现动态路由导航的示例

    目录 1.导航守卫 二.功能展示 三.原理 四.功能实现 小结 1.导航守卫 “导航” 表示路由正在发生改变 正如其名,vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航.有多种机会植入路由导航过程中:全局的, 单个路由独享的, 或者组件级的. 记住参数或查询的改变并不会触发进入/离开的导航守卫.你可以通过观察 $route 对象来应对这些变化,或使用 beforeRouteUpdate 的组件内守卫. v-router官网:https://router.vuejs.org

  • VUE+elementui面包屑实现动态路由详解

    我的路由: const routerMap = [ { path: '/', redirect: 'dashboard', component: Layout, name:'Dashboard', children: [ { path: 'dashboard', component: () => import('@/view/dashboard'), name: 'Dashboard', meta: { title: 'dashboard', icon: 'dashboard', noCache

  • Python之——生成动态路由轨迹图的实例

    一.scapy简介与安装 scapy(http://www.secdev.org/projects/scapy/)是一个强大的交互式数据包处理程序,它能够对数据包进行伪造或解包,包括发送数据包.包嗅探.应答和反馈匹配等功能.可以用在处理网络扫描.路由跟踪.服务探测.单元测试等方面,本节主要针对scapy的路由跟踪功能,实现TCP协议方式对服务可用性的探测,比如常用的80(HTTP)与443(HTTPS)服务,并生成美观的路由线路图报表,让管理员清晰了解探测点到目标主机的服务状态.骨干路由节点所处

  • 微信小程序实现的动态设置导航栏标题功能示例

    本文实例讲述了微信小程序实现的动态设置导航栏标题功能.分享给大家供大家参考,具体如下: 场景 当从一个分类列表页面进入到一个详情页面的时候,由于这个详情页面是公用的,为了区分页面,就会设置该页面的导航用以区分.就需要开发者在页面加载的时候进行动态设置导航标题! 实现API wx.setNavigationBarTitle(OBJECT) 语法 wx.setNavigationBarTitle({ title: '当前页面', //页面标题 success: () => {}, //接口调用成功的

  • Vue.js如何利用v-for循环生成动态标签

    目录 前言 一.当写入数据为数组时 二.当写入数据为对象时 三.作用于标签属性和事件 总结 前言 使用v-for可以用于动态生成html标签.其实就是对于vue中属性是对象或者数组进行遍历生成新的标签. v-for就像java中的for循环一样,迭代需要的所有元素. 大多数情况是以一个数组嵌套多个对象的数据进行v-for循环 一.当写入数据为数组时 如果循环遍历得到的value值是一个对象,需要使用里面的值可以用 对象名.key 来调用key对应的value值 v-for写入数组的格式: arr

  • vue3动态路由刷新后空白或者404问题的解决

    目录 前言 实现 登出页面需要清除缓存 排错过程 总结 前言 之前用vue+ant-design-vue写了一个动态路由的页面,更新看一下不能用了555~~~ 之前用的组件版本不知道了,回退也不知道哪个版本合适,就是用"vue": "^3.2.13" , "vue-router": "^4.0.3","vuex": "^4.0.0",ant-design-vue": "

  • vue iview实现动态路由和权限验证功能

    github上关于vue动态添加路由的例子很多,本项目参考了部分项目后,在iview框架基础上完成了动态路由的动态添加和菜单刷新.为了帮助其他需要的朋友,现分享出实现逻辑,欢迎一起交流学习. Github地址 iview-dynamicRouter 实现目标 客户端从服务端拿到路由和权限数据后,刷新项目的路由和菜单列表,并进行权限控制. 项目基础 基础框架: iview组件库官方模板项目 iview-admin 的template分支项目,此项目为 iview-admin 的基础框架代码.项目地

  • Vue 动态路由的实现及 Springsecurity 按钮级别的权限控制

    思路 : 动态路由实现:在导航守卫中判断用户是否有用户信息, 通过调用接口,拿到后台根据用户角色生成的菜单树, 格式化菜单树结构信息并递归生成层级路由表并 使用Vuex保存,通过  router.addRoutes  动态挂载到  router  上,按钮级别的权限控制,则需使用自定义指令去实现. 实现: 导航守卫代码: router.beforeEach((to, from, next) => { NProgress.start() // start progress bar to.meta

随机推荐