菜单数据列表 #

个人中心  Profile.vue
商店     Shop.vue
购物车   Cart.vue
    └── 购物车列表    CartList.vue
       ├── 商品      Product.vue
       └── 彩票      Lottery.vue

admin权限,后台返回的数据 #

[
    {pid:-1,path:'/cart',name:'购物车',id:1,auth:'cart'},
    {pid:1,path:'/cart/cart-list',name:'购物车列表',id:4,auth:'cart-list'},
    {pid:4,path:'/cart/cart-list/lottery',auth:'lottery',id:5,name:'彩票'},
    {pid:4,path:'/cart/cart-list/product',auth:'product',id:6,name:'商品'},
    {pid:-1,path:'/shop',name:'商店',id:2,auth:'shop'},
    {pid:-1,path:'/profile',name:'个人中心',id:3,auth:'store'},
];

服务端返回权限 #

let express = require('express');
let app = express();
app.all('*', function (req, res, next) {
    res.header('Access-Control-Allow-Origin', '*');
    //Access-Control-Allow-Headers ,可根据浏览器的F12查看,把对应的粘贴在这里就行
    res.header('Access-Control-Allow-Headers', 'Content-Type');
    res.header('Access-Control-Allow-Methods', '*');
    res.header('Content-Type', 'application/json;charset=utf-8');
    next();
});
app.get('/roleAuth',(req,res)=>{
    res.json({
        menuList:[
            {pid:-1,path:'/cart',name:'购物车',id:1,auth:'cart'},
            {pid:1,path:'/cart/cart-list',name:'购物车列表',id:4,auth:'cart-list'},
            {pid:4,path:'/cart/cart-list/lottery',auth:'lottery',id:5,name:'彩票'},
            {pid:4,path:'/cart/cart-list/product',auth:'product',id:6,name:'商品'},
            {pid:-1,path:'/shop',name:'商店',id:2,auth:'shop'},
            {pid:-1,path:'/profile',name:'个人中心',id:3,auth:'profile'},
        ]
    })
})
app.listen(3000);

递归菜单 #

let getMenuList = (list) => {
  let auths = [];
  function getList(pid){
    return list.filter(l=>{
      if(l.pid === pid){
        auths.push(l.auth); // 提取用户权限
        let children = getList(l.id);
        l.children = children.length>0?children:null;
        return l;
      }
    });
  }
  let menuList = getList(-1); // 通过根循环列表
  return {menuList,auths};
}

// 获取菜单列表

export default new Vuex.Store({
  state: {
    menuList:[], // 菜单列表 
    authList:[], // 权限列表
    hasAuthMenu: false // 默认没有权限菜单,如果获取菜单后改为true
  },
  mutations: {
    setMenuList(state,menuList){
      state.menuList = menuList;
    },
    authList(state,auths){
      state.authList = auths;
    },
    hasAuthMenu(state){
      state.hasAuthMenu = true;
    }
  },
  actions: {
    async getMenuList({commit}){
      let {data} = await axios.get('http://localhost:3000/roleAuth');
      let {menuList,auths} = getMenuList(data.menuList);
      commit('setMenuList',menuList);
      commit('authList',auths);
      commit('hasAuthMenu');
      return auths;
    }
  }
});

静态菜单 #

<el-menu default-active="2" class="el-menu-vertical-demo">
    <el-submenu index="1">
        <template slot="title">导航一</template>
        <el-submenu index="1-1">
        <template slot="title">选项1-1</template>
        <el-menu-item index="1-1-1">选项1-1-1</el-menu-item>
        <el-menu-item index="1-1-2">选项1-1-2</el-menu-item>
        </el-submenu>
        <el-menu-item index="1-2">选项1-2</el-menu-item>
    </el-submenu>
    <el-menu-item index="2">
        导航二
    </el-menu-item>
    <el-menu-item index="3">
        导航三
    </el-menu-item>
    <el-menu-item index="4">
        导航四
    </el-menu-item>
</el-menu>

递归组件 #

Home.vue

<template>
  <div class="home">
      <el-menu default-active="2" class="el-menu-vertical-demo" :router="true">
        <template v-for="m in menuList">
          <el-menu-item :index="m.path" :key="m.auth" v-if="!m.children">
            {{m.name}}
          </el-menu-item>
          <ReSub :m="m" :key="m.auth" v-else></ReSub>
        </template>
      </el-menu>
  </div>
</template>

ReSub.vue

<template>
    <el-submenu :index="m.auth">
          <template slot="title">
              <router-link :to="m.path">{{m.name}}</router-link>
          </template>
          <template v-for="l in m.children">
                <el-menu-item v-if="!l.children" :index="l.path" :key="l.auth">{{l.name}}</el-menu-item>
                <ReSub v-else :key="l.auth" :m="l"></ReSub>
          </template>
    </el-submenu>
</template>
<script>
export default {
    name:'ReSub',
    props:['m']
}
</script>

拆分路由 #

// 权限路由
export let authRoutes = [
  {
    path:'/cart',
    name:'cart',
    component:()=>import('@/views/menu/Cart'),
    children:[
      {
        path:'cart-list',
        name:'cart-list',
        component:()=>import('@/views/menu/CartList'),
        children:[
          {
            path:'lottery',
            name:'lottery',
            component:()=>import('@/views/menu/Lottery'),
          },
          {
            path:'product',
            name:'product',
            component:()=>import('@/views/menu/Product'),
          }
        ]
      }
    ]
  },
  {
    path:'/profile',
    name:'profile',
    component:()=>import('@/views/menu/Profile'),
  },
  {
    path:'/shop',
    name:'shop',
    component:()=>import('@/views/menu/Shop'),
  }
]

// 默认路由
let defaultRoutes = [
  {
    path: '/',
    name: 'home',
    component: Home
  },
  {
    path: '*',
    component: NotFound
  }
]

通过权限筛出路由 #

router.beforeEach(async (to,from,next)=>{
  if(!store.state.hasAuthMenu){
     // 1) 获取菜单列表
     let auths = await store.dispatch('getMenuList');
     // 2) 获取筛选后的路由
     let newRoutes = await store.dispatch('authRoutes',auths);
     // 3) 根据权限添加路由
     router.addRoutes(newRoutes);
     next({...to,replace:true});
  }else{
    next();
  }
});

// 获取路由数据
let getRoutes = (auths)=>{
  function r(authRoutes){
    return authRoutes.filter(route=>{
      // 有权限
      if(auths.includes(route.name)){
        if(route.children){ // 有孩子 递归孩子
          route.children = r(route.children);
        }
        return route;
      }
    })
  }
  return r(authRoutes);
}


//  vuex中获取晒出的路由
async authRoutes({commit},auths){
    // 全部路由  + 权限 => 晒出需要的路由
    return getRoutes(auths)
},