[ { "id": "1", "name": "菜单1", "parent_id": null, "route": "route1" }, { "id": "2", "name": "菜单1-1", "parent_id": "1", "route": "route2" } ]
资源权限数据必须是如下格式的对象数组,每个对象代表一个RESTful请求,支持带参数的url。
[ { "id": "2c9180895e172348015e1740805d000d", "name": "账号-获取", "url": "/accounts", "method": "GET" }, { "id": "2c9180895e172348015e1740c30f000e", "name": "账号-删除", "url": "/account/**", "method": "DELETE" } ]
路由控制
路由控制包括动态注册路由和动态生成菜单两部分。
动态注册路由
最初实例化的路由仅包括登录和404两个路径,我们期待完整的路由是这样的:
[{ path: '/login', name: 'login', component: (resolve) => require(['../views/login.vue'], resolve) }, { path: '/404', name: '404', component: (resolve) => require(['../views/common/404.vue'], resolve) }, { path: '/', name: '首页', component: (resolve) => require(['../views/index.vue'], resolve), children: [{ path: '/route1', name: '栏目1', meta: { icon: 'icon-channel1' }, component: (resolve) => require(['../views/view1.vue'], resolve) }, { path: '/route2', name: '栏目2', meta: { icon: 'ico-channel2' }, component: (resolve) => require(['../views/view2.vue'], resolve), children: [{ path: 'child2-1', name: '子栏目2-1', meta: { }, component: (resolve) => require(['../views/route2-1.vue'], resolve) }] }] }, { path: '*', redirect: '/404' }]
那么接下来就需要获取首页以及其子路由们,思路是事先在本地存一份整个项目的完整路由数据,然后根据用户权限对完整路由进行筛选。
筛选的实现思路是先将后端返回的路由数据处理成如下哈希结构:
let hashMenus = { "/route1":true, "/route1/route1-1":true, "/route1/route1-2":true, "/route2":true, ... }
然后遍历本地完整路由,在循环中将路径拼接成上述结构中的key格式,通过hashMenus[route]就可以判断路由是否匹配,具体实现见App.vue文件中的getRoutes()方法。
如果后端返回的路由权限数据与约定不同,就需要自行实现筛选逻辑,只要能得到实际可用的路由数据就可以,最终使用addRoutes()方法将他们动态添加到路由实例中,注意404页面的模糊匹配一定要放在最后。
动态菜单
路由数据可以直接用来生成导航菜单,但路由数据是在根组件中得到的,导航菜单存在于index.vue组件中,显然我们需要通过某种方式共享菜单数据,方法有很多,一般来说首先想到的是Vuex,但菜单数据在整个用户会话过程中不会发生改变,这并不是Vuex的最佳使用场景,而且为了尽量减少不必要的依赖,这里用了最简单直接的方法,把菜单数据挂在根组件data.menuData上,在首页里用this.$parent.menuData获取。