关于vue动态权限的处理与nav导航栏的处理


最近在写一个基于vue的动态权限,由于没有在前端做过动态权限,看了一下vue-element-admin是前端写的动态路由,就试着仿写了一下。

首先是路由表

// 这是在 router 的index.js中

export const constantRouterMap = [  // 静态路由,所有用户都能访问的路由
  {
    hidden: true,
    path: "/login",
    component: Login
  },
  {
    hidden: true,
    path:"/404",
    component: NotFind
  }
]

export const asyncRouterMap = [  // 动态路由,只有指定meta.role里面的角色能访问
	{
		path: "/",
    icon:"iconfont icon-yibiaopan",
		redirect: "/dashboard",
		component: Home,
		children: [{
			path: "/dashboard",
			name: "首页",
			icon:"iconfont icon-yibiaopan",
			component: Dashboard,
      meta: {
        activePath: "/dashboard"
      }
		}]
	},
  {
    path: "/system_manage",
    redirect: "/system_manage/manage_list",
    name: "系统管理",
    icon: "iconfont icon-xitongguanli-",
    meta: {
      role: ['Root'],
      breadCrumbRole: ["Root"]
    },
    component: Home,
    children: [
      {
        path: "/system_manage/manage_list",
        name: "系统管理员列表",
        icon: "iconfont icon-xitongguanliyuan",
        meta: {
          role: ['Root'],
          activePath: "/system_manage/manage_list",
          breadCrumbRole: ["Root"]
        },
        component: AdminList
      },
      {
        path: "/system_manage/role_list",
        name: "角色列表",
        icon: "iconfont icon-role-list",
        meta: {
          role: ['Root'],
          activePath: "/system_manage/role_list",
          breadCrumbRole: ["Root"]
        },
        component: RoleList
      },
      {
        path: "/system_manage/power_list",
        name: "权限列表",
        icon: "iconfont icon-quanxianliebiao",
        meta: {
          role: ['Root'],
          activePath: "/system_manage/power_list",
          breadCrumbRole: ["Root"]
        },
        component: PowerList
      }
    ]
  },
  {
    hidden: true,
    path: "*",
    redirect: '/404'
  }
]

对于最终的路由表处理我和vue-element-admin一样,创建了一个vuex模块来管理,其中做了一些更改

import { asyncRouterMap, constantRouterMap } from "router/index"
/**
 *
 * @param [用户拥有的角色] roles
 * @param [路由需要的角色] route
 */
function hasPermission(roles, route) {
  // 如果当前路由含有 meta.role 属性,则判断用户的角色有没有至少一个在所需角色里面
  if (route.meta && route.meta.role) {
    return roles.some(role => route.meta.role.indexOf(role) >= 0)
  } else {
    return true
  }
}

const state = {
  routers: constantRouterMap,  // 静态路由
  addRouters: [],   // 要添加的动态路由,之后会被拼接到上面的routers中
  isAddRoutes: false    // 设置是否已加载动态路由的状态,对于刷新之后空白的处理我是在路由的beforeEach中处理的,先判断有没有动态添加。
}

const getters = {
  routers() {
    return state.routers
  },
  isAddRoutes() {
    return state.isAddRoutes
  }
}

const mutations = {
  SET_ROUTERS(state, routers) {
    state.addRouters = routers
    state.routers = constantRouterMap.concat(routers)   // 拼接路由
  },
  SET_ADD_STATUS(state) {
    state.isAddRoutes = true
  }
}

const actions = {
  // 生成过滤后的路由
  GenerateRoutes({ commit }, roles = []) {
    return new Promise(resolve => {
      // 过滤动态路由列表
      const accessedRouters = asyncRouterMap.filter(v => {
        // 如果传过来的roles中含有 Root 管理员角色,则直接返回true,不进行过滤
        if (roles.indexOf('Root') >= 0) return true;
        // 不是则进行权限判断
        if (hasPermission(roles, v)) {
          // 拥有权限返回true
          if (v.children && v.children.length > 0) {
            v.children = v.children.filter(child => {
              if (hasPermission(roles, child)) {
                return child
              }
              return false;
            });
            return v
          } else {
            return v
          }
        }
        return false;
      });
      console.log(accessedRouters);
      commit('SET_ROUTERS', accessedRouters);
      commit("SET_ADD_STATUS")
      resolve(accessedRouters);
    })
  }
}

export default {
  namespaced: true,
  state,
  mutations,
  actions,
  getters
}

这样一来动态路由就好了,然后nav菜单栏。

nav菜单栏也是跟vue-element-admin一样,做了两层,将每一个菜单都用一个组件来渲染。数据则用的是动态路由的数据,前面已经加了hidden属性来控制

要显示的菜单栏,对于高亮当前选中的菜单问题,我在meta另外加了个activePath用来专门显示活跃的菜单(基于elementui)。

// 首先是父组件
<template>
  <div class="siderbar_container" :style="{width:sideHidden?'64px':'200px'}">
    <el-menu
            :default-active="$route.meta.activePath"
            background-color="#545c64"
            text-color="#fff"
            active-text-color="#ffd04b"
            :collapse="sideHidden"
            :collapse-transition="false"
            style="width:100%;"
            router
            unique-opened
    >
      <!-- 循环一级菜单 -->
      <SideBarItem v-for="route in menuList" :item="route" :key="route.path" />

    </el-menu>
  </div>
</template>


// 子组件
<template>
  <div>
    <!-- 判断该路由的显示状态 -->
    <template v-if="!item.hidden">
      <!-- 如果没有子路由则用 el-menu-item  -->
      <el-menu-item :index="item.path" v-if="!item.children">
        <i :class="[item.icon,'side_iconfont']"></i>
        <span slot="title">{{item.name}}</span>
      </el-menu-item>

      <!-- 如果有子路由则用 el-submenu  -->
      <template v-else>
        <!-- 如果子路由只有一个,则只显示这个子路由 -->
        <template v-if="item.children.length === 1">
          <SideBarItem :item="item.children[0]"></SideBarItem>
        </template>

        <el-submenu :index="item.path" v-else :key="item.path">
          <template slot="title">
            <i :class="[item.icon,'side_iconfont']"></i>
            <span>{{item.name}}</span>
          </template>
          <!-- 调用组件自己,形成递归 -->
          <SideBarItem v-for="child in item.children" :key="child.path" :item="child"></SideBarItem>
        </el-submenu>
      </template>
    </template>
  </div>
</template>

这样一来菜单栏跟动态路由就都好了。
对于退出登录后切换账号,权限重复的处理,我是在登录页面的create作判断,来重新载入页面

created() {
    let isAddRoutes = this.$store.getters["permission/isAddRoutes"]
    if(isAddRoutes) {
      console.log("已经动态加载了route,刷新页面");
      return window.location.reload()
    }
  }


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM