vue+element-ui實(shí)現(xiàn)動(dòng)態(tài)的權(quán)限管理和菜單渲染

前言:

需求:需要根據(jù)不用的用戶匹配不同的管理權(quán)限,既:匹配不同的操作導(dǎo)航,尤其體現(xiàn)在后臺(tái)管理系統(tǒng)內(nèi),如果僅僅只是在導(dǎo)航菜單內(nèi)不予顯示,仍然是可以通過(guò)路徑直接打開頁(yè)面,因?yàn)槠渎酚尚畔⒁呀?jīng)在路由信息對(duì)象(new Router({}))函數(shù)中進(jìn)行了注冊(cè)

當(dāng)然 這里可以通過(guò)全局導(dǎo)航守衛(wèi)來(lái)區(qū)分不同的用戶,允許其進(jìn)入不同的路徑,但是這只能進(jìn)行簡(jiǎn)單的權(quán)限判斷,且前端已經(jīng)寫死,靈活性不高,不能針對(duì)每個(gè)用戶,做定制化權(quán)限區(qū)分

項(xiàng)目地址:https://github.com/cgq001/vue-admin

歡迎start

使用到的規(guī)則

1、動(dòng)態(tài)設(shè)置權(quán)限的UI展示

這里使用element-ui的Three樹形控件,數(shù)據(jù)結(jié)構(gòu)如下:

data: [{
          id: 1,
          label: '一級(jí) 1',
          children: [{
            id: 4,
            label: '二級(jí) 1-1',
            children: [{
              id: 9,
              label: '三級(jí) 1-1-1'
            }, {
              id: 10,
              label: '三級(jí) 1-1-2'
            }]
          }]
        }, {
          id: 2,
          label: '一級(jí) 2',
          children: [{
            id: 5,
            label: '二級(jí) 2-1'
          }, {
            id: 6,
            label: '二級(jí) 2-2'
          }]
        }, {
          id: 3,
          label: '一級(jí) 3',
          children: [{
            id: 7,
            label: '二級(jí) 3-1'
          }, {
            id: 8,
            label: '二級(jí) 3-2'
          }]
        }]

這里選擇這個(gè)樹形控件,是因?yàn)槠鋽?shù)據(jù)結(jié)構(gòu)和我們的 注冊(cè)路由信息結(jié)構(gòu)十分接近,不需要再重新修改路由信息的數(shù)據(jù)結(jié)構(gòu),即可完美的 展現(xiàn)在 Three樹形控件里

2、將側(cè)邊導(dǎo)航所需要的路由信息對(duì)象 抽離成一個(gè)數(shù)組,根據(jù)后臺(tái)返回的數(shù)組,篩選出對(duì)應(yīng)的路由信息,通過(guò)addRoutes添加到路由信息對(duì)象里,即可完成路由信息的動(dòng)態(tài)添加

詳情

// 在router.js 路由文件 新建數(shù)組路由存儲(chǔ) '/'  父路由下的所有子路由(這里所有的動(dòng)態(tài)路由均為 '/' 的子路由)
let routerLists=[ 
  {
    id:1,
    path: '',
    label: '首頁(yè)',
    redirect: '/index',  //重定向到
    meta:{
      title: '首頁(yè)',
      table: true,
      display: false,
      icon: 'el-icon-s-home'
    }
  },
  {
    id: 2,
    path: '/index',   
    name: 'index',
    label: '首頁(yè)',
    component: _import('Index/Index'),
    meta:{
      title: '首頁(yè)',
      table: true,
      display:true,
      icon: 'el-icon-s-home'
    }
  },
  {
    id: 3,
    path: '/shop',
    name: 'shop',
    label: '商品管理',
    component: _import('Shop/Shop'),
    meta:{
      title: '商品列表',
      table: true,
      display:true,
      icon: 'el-icon-s-operation'
    }
  },
  {
    id:20,
    path: '/admin',
    label: '管理員列表',
    component: _import('admin/index'),
    meta:{
        title: '管理員列表',
        table: true,
        display:true,
        icon: 'el-icon-s-custom'
    },
    children:[
      {
        id:21,
        path: '/admin/index',
        label: '管理員列表',
        component: _import('admin/admin'),
        meta:{
          title: '管理員列表',
          table: true,
          display:true,
          icon:'el-icon-tickets'
        }
      },
      {
        id:22,
        path: '/admin/adminlist',
        label: '添加管理員',
        component: _import('admin/adminlist'),
        meta:{
          title: '添加管理員',
          table: true,
          display:true,
          icon:'el-icon-document-remove'
        }
      }
    ]
  }
]

//定義 上面數(shù)組的父路由
let routerAlls=[   //這里為routerLists的父路由
        {
          path: '/',
          component: Home
        }
]

1 .權(quán)限配置表
// 先把路由信息對(duì)象字符串化,然后去除component字段 ,再傳遞給 權(quán)限配置表
 let routerListString =JSON.stringify(routerLists)
 let src= routerListStr(routerListString)
 store.commit('serRouterList',src)

 let arr=[1,2,3,20,21,22]   //這里為權(quán)限列表數(shù)組(既后臺(tái)根據(jù)用戶身份返回的對(duì)應(yīng)的路由數(shù)組)

 //根據(jù)權(quán)限配置表(arr數(shù)組)和動(dòng)態(tài)路由信息對(duì)象(routerLists數(shù)組) 獲取本用戶的路由信息表,并添加到 routerAlls 路由的二級(jí)路由里
 
 2.獲取動(dòng)態(tài)路由
 
routerAlls[0].children = routerListFun(arr,routerLists)  
//獲取 路徑 '/' 的子路由,并添加至 routerAlls   這里的  routerListFun函數(shù) 為 根據(jù)權(quán)限列表數(shù)組(arr)篩選動(dòng)態(tài)路由信息對(duì)象(routerLists) PS:函數(shù)內(nèi)容見 文章末尾:附錄


3.獲取側(cè)邊導(dǎo)航欄 的 渲染菜單 數(shù)組

//根據(jù)權(quán)限配置表數(shù)組(arr)和動(dòng)態(tài)路由信息對(duì)象(routerLists) 獲取本用戶的菜單列表
let mentParse =JSON.parse(JSON.stringify(src))
let menuList = routerListFun(arr,mentParse)   //這里routerListFun函數(shù)注意去除返回?cái)?shù)組中的component
store.commit('setMents',menuList)   //將其添加到vuex  


// 注冊(cè)路由
let routers =new Router({
  mode: 'history',
  // base: process.env.BASE_URL,
  routes: [
    {
      path: '/loading',
      name: 'loading',
      component: () => import('../views/Load/Loading.vue'),
      meta:{
        title: '登陸',
        table: false
      }
    }
  ]
})

// 將篩選后的路由信息對(duì)象添加至路由表
routers.addRoutes(routerAlls)


// 進(jìn)行全局導(dǎo)航守衛(wèi)
routers.beforeEach((to,from,next)=>{
    
      if(to.path != '/loading'){
          
          let username=store.state.load.userList.username
          
          if(username){
            next()
          }else{

            next({
              path:'/loading',
              query:{
                path:to.path
              }
            }) 
          }
      }else{
        next()
      }   
})

export default routers;

附錄

1.動(dòng)態(tài)路由書寫規(guī)則

* 路由書寫規(guī)則
 *    1、只有一級(jí)路由(實(shí)際為二級(jí)路由):
 *     {
          id: 2,                                  //ID全局不能重復(fù)
          path: '/index',                         //路由路徑 全局不能重復(fù)
          name: 'index',                          //名字,全局不能重復(fù),存在二級(jí)路由,則一級(jí)路由不能有名字
          label: '首頁(yè)',                          // 頁(yè)面名稱(用于權(quán)限配置時(shí) 顯示名稱使用)
          component: _import('Index/Index'),      // 文件地址(此處對(duì)應(yīng)的是views目錄)
          meta:{
            title: '首頁(yè)',                        //頁(yè)面名稱(橫向teble標(biāo)簽切換)
            table: true,                          // 是否顯示 teable 切換按鈕
            display:true,                         //  是否在側(cè)邊導(dǎo)航菜單顯示
            icon: 'el-icon-s-home'                //  側(cè)邊導(dǎo)航的icon圖標(biāo)
          }
        }
      2、包含二級(jí)路由(實(shí)際為三級(jí)路由)
        {
            id:20,                                  //ID全局不能重復(fù)
            path: '/admin',                         //路由路徑 全局不能重復(fù)(此處為父級(jí)))
            label: '管理員列表',                     // 頁(yè)面名稱(用于權(quán)限配置時(shí) 顯示名稱使用)
            component: _import('admin/index'),      // 文件地址(此處對(duì)應(yīng)的是views目錄)注意:此文件下 應(yīng)包含(router-view 標(biāo)簽 來(lái)顯示子頁(yè)面)
            meta:{
                title: '管理員列表',                   //頁(yè)面名稱(橫向teble標(biāo)簽切換)
                table: true,
                display:true,                         //  是否在側(cè)邊導(dǎo)航菜單顯示(注意 這里是父級(jí),如果為false,則子級(jí)不在折疊)
                icon: 'el-icon-s-custom'              //  側(cè)邊導(dǎo)航的icon圖標(biāo)
            },
            children:[
              {
                id:21,                              //ID全局不能重復(fù)
                path: '/admin/index',               //路由路徑 全局不能重復(fù)(此處為父級(jí)))
                label: '管理員列表',                  // 頁(yè)面名稱(用于權(quán)限配置時(shí) 顯示名稱使用)
                component: _import('admin/admin'),   // 文件地址(此處對(duì)應(yīng)的是views目錄)
                meta:{
                  title: '管理員列表',                //頁(yè)面名稱(橫向teble標(biāo)簽切換)
                  table: true,                      // 是否顯示 teable 切換按鈕
                  display:true,                     //  是否在側(cè)邊導(dǎo)航菜單顯示
                  icon:'el-icon-tickets'            //  側(cè)邊導(dǎo)航的icon圖標(biāo)
                }
              }
            ]
          }

2.routerListFun、routerListStr函數(shù)

// 根據(jù)后臺(tái)返回的權(quán)限數(shù)組,篩選對(duì)應(yīng)的路由信息對(duì)象
export function routerListFun(arr,allList){


    let arrArray=[]
            
    for(let i=0;i<arr.length;i++){
        
        for(let k=0;k<allList.length;k++){
            if(arr[i] == allList[k].id){
                arrArray.push(allList[k])
            }
        }
    }
    
    
    
    for(let i=0;i<arrArray.length;i++){
        if(arrArray[i].children && arrArray[i].children.length>0){
            arrArray[i].childrens=[]
            for(let k=0;k<arrArray[i].children.length;k++){
                for(let j=0;j<arr.length;j++){
                    if(arrArray[i].children[k].id == arr[j]){
                        arrArray[i].childrens.push(arrArray[i].children[k])
                    }
                }
            }
            arrArray[i].children=arrArray[i].childrens
        }
    }
    return arrArray;
}

// 根據(jù)全部的路由信息對(duì)象 返回 權(quán)限列表

export function  routerListStr(routerStr){
    
        let routerJson= JSON.parse(routerStr)
        for(let i=0;i<routerJson.length;i++){
            if(routerJson[i].component){
                routerJson[i].component=''
            }

            if(routerJson[i].children && routerJson[i].children.length>0){
                for(let k=0;k<routerJson[i].children.length;k++){
                    routerJson[i].children[k].component=''
                }
            }
        }

        return routerJson;
}

3.路由渲染

<!-- 這里的 routerList  為 從 router.js動(dòng)態(tài)獲取到了路由信息 -->
 <div v-for="item in routerList" :key="item.id" >
        <!--包含二級(jí)導(dǎo)航-->
        <el-submenu :index="item.id.toString()" v-if="item.children && item.children.length > 0 && item.meta.display==true">
                        <template slot="title">
                            <i :class="item.meta.icon"></i>
                            <span>{{item.label}}</span>
                        </template>
                <el-menu-item v-show="items.meta.display" v-for="(items,indexs) in item.children" :key="indexs" :index="items.path">
                            <i :class="items.meta.icon"></i>
                            {{items.label}}
                </el-menu-item>
        </el-submenu>
        <!-- 如果 二級(jí)導(dǎo)航的 父級(jí) 設(shè)置display:false  則直選渲染二級(jí)導(dǎo)航為一級(jí)導(dǎo)航 -->
       <el-menu-item v-for="(items,indexs) in item.children" :key="indexs" :index="items.path" v-show="items.meta.display"  v-else-if="item.children && item.children.length > 0 && item.meta.display==false" >
                        <i :class="item.meta.icon"></i>
                        <span slot="title">{{item.label}}</span>
         </el-menu-item>
        <!-- 渲染一級(jí)導(dǎo)航 -->
        <el-menu-item  v-show="item.meta.display" :index="item.path"  v-else >
                        <i :class="item.meta.icon"></i>
                        <span slot="title">{{item.label}}</span>
        </el-menu-item>
    </div>
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,667評(píng)論 1 32
  • 最近幾年,在外地到處都能聽見吃火鍋,就上海底撈的廣告,同事們也常說(shuō)海底撈的服務(wù)特別的棒,于是趁著這次出差,與同事們...
    承鴻閱讀 789評(píng)論 2 1
  • 南風(fēng)是春天的信使。 一早上起來(lái)時(shí),看向窗外,天空亮了,隱約有朝霞的影子在浮動(dòng)。大霧籠罩下的林...
    HR_欣姐閱讀 454評(píng)論 0 1

友情鏈接更多精彩內(nèi)容