關於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