vue使用动态添加路由(router.addRoutes)加载权限侧边栏的方式
作者:上条当杨
工作中我们经常会遇到这种需求,后台定义用户的权限数据,前端进行获取,并渲染在侧边栏导航上,不同权限的用户看到的侧边栏是不同的。
即前端渲染的数据是随着后台的改变而改变的,做到真正的前后端分离。
一、拿到需要动态添加的路由表
我们的思路是:
登录(login,所有人均可见)--------->登录成功,获取权限-------->权限不同,侧边栏的数据展示不同
先定义一份公共的路由表,里面仅有一些公共的路由,如 login
获取到权限后,我们根据权限,得到需要动态添加的路由表,把这份路由表动态添加到router中即可。
通过查阅网上的资料,论坛等我总结出了2条方式,分别是前端主导和后台主导。
(1)前端主导
何谓前端主导?就是在整个权限方面,主体是定义在前端。前端需要提前定义一份完整的路由权限表,后台的作用仅仅是返回当前用户的权限列表,把获取到的权限表比对完整的权限表,那么得到一份新的路由权限表拿去渲染。
这里需要注意的是,为什么不直接把后台返回的权限列表拿去渲染,而是需要通过比对,才得出权限表?
因为后台返回的仅仅只是字符串!
我们在使用vue-router定义路由的时候,是需要导入该路由对应的component的,如下所示, component是必须引入的,而后台返回给我们的数据是不会带component对应的组件的。
import Login from './views/Login.vue' let publicRoutes = [ { path: '/login', name: 'login', component: Login } ]
因此我们可以在前端通过提前定义一份全部的,完整的路由表,把后台传的数据当参考使用,从而得出一份路由权限表。
举个例子:
在前端定义的完整权限表:
import Order from './components/orderCompontents/order.vue' import OrderList from './components/orderCompontents/orderList.vue' import ProductManage from './components/orderCompontents/productManage.vue' import ProductionList from './components/orderCompontents/productionList.vue' import ReviewManage from './components/orderCompontents/reviewManage.vue' import ReturnGoods from './components/orderCompontents/returnGoods.vue' const allroutes = [ { path: '/order', title: 'order-manage', component: Order, meta: { name: '订单管理' }, children: [ { path: '/order-list', title: 'order-list', component: OrderList, meta: { name: '订单列表' } }, { path: '/product', title: 'product-manage', component: ProductManage, meta: { name: '生产管理' }, children: [ { path: '/product-list', title: 'product-list', component: ProductionList, meta: { name: '生产列表' } }, { path: '/review-manage', title: 'review-manage', component: ReviewManage, meta: { name: '审核管理' } } ] }, { path: '/return-goods', title: 'return-goods', component: ReturnGoods, meta: { name: '退货管理' } } ] } ]
后台传输过来的数据:
{ "code": 0, "message": "获取权限成功", "data": [ { "name": "订单管理", "children": [ { "name": "订单列表" }, { "name": "生产管理", "children": [ { "name": "生产列表" } ] }, { "name": "退货管理" } ] } ] }
我们对比这两个数据的name属性,就能很轻易的过滤出一份路由权限表。再通过router.addRoutes()动态添加进路由即可。
(2)后台主导
前面一种方式比较简单,前端定义好,后台传过来进行比对即可,但是缺点也是很明显。
如果后台传递的权限名稍稍做一些改动,那么前端就匹配不到相应的路由了。也就是改一个权限名,前端后台需要一起改。。有点不太符合前后端彻底分离的思想。
我们想要的是,只改后台,那么前端会根据接收的数据自动变化! 怎么解决这个问题呢? 那就是用后台主导思想。
思路如下:
路由表不在前端进行比对,后台对用户的权限进行比对,返回给前端一个比对好的路由表,且返回的路由表需要有如下字段:
{ "data": { "router": [ { "path": "", "redirect": "/home", }, { "path": "/home", "component": "Home", "name": "Home", "meta": { "title": "首页", "icon": "example" }, "children": [ { "path": "/xitong", "name": "xitong", "component": "xitong/xitong", "meta": { "title": "系统", "icon": "table" } } ] }, { "path": "*", "redirect": "/404", "hidden": true } ] } }
注意其中的component字段,他是字符串,我们需要把这个字符串转化为我们前端定义的组件!
function filterRouter(routers) { // 遍历后台传来的路由字符串,转换为组件对象 const accessedRouters = routers.filter(route => { if (route.component) { if (route.component === 'Home') { // Home组件特殊处理 route.component = Home } else { route.component = _import(route.component) } } if (route.children && route.children.length) { route.children = filterRouter(route.children) } return true }) return accessedRouters }
这个函数的主要作用就是把后台传过来的字符串型的component转化为真正的组件
其中_import()函数的定义如下:
function _import (file) { return () => import('@/components/views/' + file + '.vue') }
通过异步加载组件,去请求该组件
其中的路径需要大家根据自己文件的路径去修改。
这种方法最重要的一点就是,后台传递的component实际存放的是路径!前端根据这个路径去找到这个组件并异步加载组件。
最终执行结束后,filterRouter返回的就是一份路由权限列表,里面的component也有了引用。
这种方法的好处在于,前端的所有权限路由数据都来自于后台,只要路径不改,后台任意修改数据,前端均会自动变化。
注意: 如果后台修改的是字段 “component ” 的时候,前端需要修改文件名进行配合,若是其他修改前端则均无需任何更改。
二、渲染数据到侧边栏
通过 (一) 的方式我们可以拿到一份要渲染的路由表,我是存到了vuex中,然后在sideBar页面中拿出来,渲染。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。