美文网首页Vue自我学习经历
vue+element-ui实现动态的权限管理和菜单渲染

vue+element-ui实现动态的权限管理和菜单渲染

作者: 大菜鸟呀 | 来源:发表于2019-10-04 20:32 被阅读0次

    前言:

    需求:需要根据不用的用户匹配不同的管理权限,既:匹配不同的操作导航,尤其体现在后台管理系统内,如果仅仅只是在导航菜单内不予显示,仍然是可以通过路径直接打开页面,因为其路由信息已经在路由信息对象(new Router({}))函数中进行了注册

    当然 这里可以通过全局导航守卫来区分不同的用户,允许其进入不同的路径,但是这只能进行简单的权限判断,且前端已经写死,灵活性不高,不能针对每个用户,做定制化权限区分

    项目地址:https://github.com/cgq001/vue-admin

    欢迎start

    使用到的规则

    1、动态设置权限的UI展示

    这里使用element-ui的Three树形控件,数据结构如下:

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

    这里选择这个树形控件,是因为其数据结构和我们的 注册路由信息结构十分接近,不需要再重新修改路由信息的数据结构,即可完美的 展现在 Three树形控件里

    2、将侧边导航所需要的路由信息对象 抽离成一个数组,根据后台返回的数组,筛选出对应的路由信息,通过addRoutes添加到路由信息对象里,即可完成路由信息的动态添加

    详情

    // 在router.js 路由文件 新建数组路由存储 '/'  父路由下的所有子路由(这里所有的动态路由均为 '/' 的子路由)
    let routerLists=[ 
      {
        id:1,
        path: '',
        label: '首页',
        redirect: '/index',  //重定向到
        meta:{
          title: '首页',
          table: true,
          display: false,
          icon: 'el-icon-s-home'
        }
      },
      {
        id: 2,
        path: '/index',   
        name: 'index',
        label: '首页',
        component: _import('Index/Index'),
        meta:{
          title: '首页',
          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'
            }
          }
        ]
      }
    ]
    
    //定义 上面数组的父路由
    let routerAlls=[   //这里为routerLists的父路由
            {
              path: '/',
              component: Home
            }
    ]
    
    1 .权限配置表
    // 先把路由信息对象字符串化,然后去除component字段 ,再传递给 权限配置表
     let routerListString =JSON.stringify(routerLists)
     let src= routerListStr(routerListString)
     store.commit('serRouterList',src)
    
     let arr=[1,2,3,20,21,22]   //这里为权限列表数组(既后台根据用户身份返回的对应的路由数组)
    
     //根据权限配置表(arr数组)和动态路由信息对象(routerLists数组) 获取本用户的路由信息表,并添加到 routerAlls 路由的二级路由里
     
     2.获取动态路由
     
    routerAlls[0].children = routerListFun(arr,routerLists)  
    //获取 路径 '/' 的子路由,并添加至 routerAlls   这里的  routerListFun函数 为 根据权限列表数组(arr)筛选动态路由信息对象(routerLists) PS:函数内容见 文章末尾:附录
    
    
    3.获取侧边导航栏 的 渲染菜单 数组
    
    //根据权限配置表数组(arr)和动态路由信息对象(routerLists) 获取本用户的菜单列表
    let mentParse =JSON.parse(JSON.stringify(src))
    let menuList = routerListFun(arr,mentParse)   //这里routerListFun函数注意去除返回数组中的component
    store.commit('setMents',menuList)   //将其添加到vuex  
    
    
    // 注册路由
    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
          }
        }
      ]
    })
    
    // 将筛选后的路由信息对象添加至路由表
    routers.addRoutes(routerAlls)
    
    
    // 进行全局导航守卫
    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.动态路由书写规则

    * 路由书写规则
     *    1、只有一级路由(实际为二级路由):
     *     {
              id: 2,                                  //ID全局不能重复
              path: '/index',                         //路由路径 全局不能重复
              name: 'index',                          //名字,全局不能重复,存在二级路由,则一级路由不能有名字
              label: '首页',                          // 页面名称(用于权限配置时 显示名称使用)
              component: _import('Index/Index'),      // 文件地址(此处对应的是views目录)
              meta:{
                title: '首页',                        //页面名称(横向teble标签切换)
                table: true,                          // 是否显示 teable 切换按钮
                display:true,                         //  是否在侧边导航菜单显示
                icon: 'el-icon-s-home'                //  侧边导航的icon图标
              }
            }
          2、包含二级路由(实际为三级路由)
            {
                id:20,                                  //ID全局不能重复
                path: '/admin',                         //路由路径 全局不能重复(此处为父级))
                label: '管理员列表',                     // 页面名称(用于权限配置时 显示名称使用)
                component: _import('admin/index'),      // 文件地址(此处对应的是views目录)注意:此文件下 应包含(router-view 标签 来显示子页面)
                meta:{
                    title: '管理员列表',                   //页面名称(横向teble标签切换)
                    table: true,
                    display:true,                         //  是否在侧边导航菜单显示(注意 这里是父级,如果为false,则子级不在折叠)
                    icon: 'el-icon-s-custom'              //  侧边导航的icon图标
                },
                children:[
                  {
                    id:21,                              //ID全局不能重复
                    path: '/admin/index',               //路由路径 全局不能重复(此处为父级))
                    label: '管理员列表',                  // 页面名称(用于权限配置时 显示名称使用)
                    component: _import('admin/admin'),   // 文件地址(此处对应的是views目录)
                    meta:{
                      title: '管理员列表',                //页面名称(横向teble标签切换)
                      table: true,                      // 是否显示 teable 切换按钮
                      display:true,                     //  是否在侧边导航菜单显示
                      icon:'el-icon-tickets'            //  侧边导航的icon图标
                    }
                  }
                ]
              }
    

    2.routerListFun、routerListStr函数

    // 根据后台返回的权限数组,筛选对应的路由信息对象
    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;
    }
    
    // 根据全部的路由信息对象 返回 权限列表
    
    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动态获取到了路由信息 -->
     <div v-for="item in routerList" :key="item.id" >
            <!--包含二级导航-->
            <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>
            <!-- 如果 二级导航的 父级 设置display:false  则直选渲染二级导航为一级导航 -->
           <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>
            <!-- 渲染一级导航 -->
            <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>
    

    相关文章

      网友评论

        本文标题:vue+element-ui实现动态的权限管理和菜单渲染

        本文链接:https://www.haomeiwen.com/subject/trvspctx.html