需求
最近接手一个后台管理系统,需要实现导航菜单从后台拉取的效果;根据登录用户的权限不同分别拉出来的导航菜单也不一样,另外可操作的界面也存在区别。
问题
因为后台管理系统是准备使用vue+vue-router+element-ui+vuex的搭配来做的,可是单页应用在进入页面之前就已经将vue-router实例化并且注入vue实例中了,所以在进入登录页面的时候旧没办法在重新定制路由了。接下来各种百之谷之,发现vue-router在2.0版本中提供了addRoutes方法添加路由,希望的曙光出现。
经过一番折腾终于实现了功能,记录下来便于回顾,也希望能帮助到同样有需求的同志。
思路
1、首先在本地配置好固定不变的路由地址,例如登录,404这些页面,如下:
let router = new Router({
routes: [
{
path: '/login',name: 'login',meta: {requireAuth: false},// 模块使用异步加载
component: (resolve) => require(['../components/login/login.vue'],resolve)
}]
})
//
拦截登录,token验证
router.beforeEach((to,from,next) => {
if (to.
Meta.requireAuth === undefined) {
if (store.state.token) {
next()
} else {
next({
path: '/login'
})
}
} else {
next()
}
})
export default router
配置好这些固定的路由后我们才能够到登录页面,不然是无法继续下去的。
2、然后重要的一步,我们需要跟后端老铁约定好需要返回的权限菜单列表信息;首先这里我们先分析一下自己需要的路由结构,这里以我自己的路由作为例子。如果是我自己直接定义路由的话,会是以下结构:
require(['../components/login/login.vue'],resolve)
},
{
path: '/',redirect: '/layout'
},{
path: '/layout',component: (resolve) => require(['../layout.vue'],resolve),children: [
{
path: 'index',
Meta: {
type: '1',//控制是否
显示隐藏 1
显示,2隐藏
code: 00010001,// 后面需要控制路由高亮
title: '
首页',//
菜单名称
permissonList: [] // 权限列表
}
component: (resolve) => require(['@/components/index/index.vue'],resolve)
},{
...
}
]
}]
})
根据以上结构分析,其实真正需要动态配置的路由其实是/layout下面的children部分,所以需要后端返回给我们包含所有路由的一个数组就可以了
功能,只是作为切换二级菜单的触发器,subList才是我们真正需要的路由信息。
{
this.loging = false
console.info('
菜单列表:',res)
if (res.resultCode === this.$state_ok) {
// 合并一级
菜单和二级
菜单,便于
显示
let menus = handleMenu.mergeSubInRoot(res.rootList,res.subList)
// 本地化处理好的
菜单列表
this.saveRes({label: 'menuList',value: menus})
// 根据subList处理路由
let routes = handleMenu.mergeRoutes(res.subList)
// 本地化subList,便于在刷新
页面的时候重新配置路由
this.saveRes({label: 'subList',value: res.subList})
// 防止重复配置相同路由
if (this.$router.options.routes.length <= 1) {
this.$router.addRoutes(routes)
// this.$router不是响应式的,所以手动将路由元注入路由对象
this.$router.options.routes.push(routes)
}
this.$router.replace('/layout/index')
}
})
.catch((err) => {
this.loging = false
console.error('
错误:',err)
})
},
处理菜单列表和subList的方法:mergeSubInRoot 和 mergeRoutes
菜单和子
菜单
* @param: rootList [Array] 主
菜单列表
* @param: subList [Array] 子
菜单
* */
mergeSubInRoot (roots,subs) {
if (roots && subs) {
for (let i = 0; i < roots.length; i++) {
let rootCode = roots[i].code
roots[i].children = []
for (let j = 0; j < subs.length; j++) {
if (rootCode === subs[j].code.substring(0,4)) {
roots[i].children.push(subs[j])
}
}
}
}
return roots
},/**
* 合并远程路由到本地路由
* @param: subList [Array] 远程路由列表
* @param: routes [Array] 本地路由列表
* */
mergeRoutes (subs) {
if (subs) {
for (let i = 0; i < subs.length; i++) {
let temp = {
path: subs[i].actUrl,name: subs[i].actUrl,component: (resolve) => require([`@/components/${subs[i].component}.vue`],
Meta: {
type: subs[i].type,code: subs[i].code,title: subs[i].name,permissionList: subs[i].permissionList
}
}
routes[1].children.push(temp)
}
}
return routes
}
}
至此我们已经将权限路由成功配置进本地路由了,我的系统登录进入如下
后续优化
1、菜单列表的显示以及二级导航切换:
<script type="text/ecmascript-6">
import {mapState,mapMutations} from 'vuex'
export default {
name: 'menu',data () {
return {
msg: 'Welcome to Your Vue.js App'
}
},computed: {
...mapState(['menuList']),activeCode () {
// 通过code保证在切换字路由的情况下一级路由也是高亮显示
return this.$route.Meta.code.substring(0,4)
}
},methods: {
...mapMutations(['saveRes']),// 切换二级路由
switchSubMenu (route) {
console.info('路由:',route)
if (route.actUrl !== 'index') {
// 用currentSubMenu控制二级路由数据
this.saveRes({label: 'currentSubMenu',value: route.children})
this.$router.push(/layout/${route.children[0].actUrl}
)
} else {
// 不存在二级路由隐藏二级
this.saveRes({label: 'currentSubMenu',value: ''})
this.$router.push(/layout/${route.actUrl}
)
}
}
},filters: {
splitCode (code) {
return code.substring(0,4)
}
}
}
2、防止刷新路由丢失;由于在刷新的时候单页应用会重新初始化,这时候所有配置的路由都会丢失,一朝回到解放前,只有本地配置的路由能够跳转。这时候我们可以在app.vue(ps:不论在哪里进行刷新,app.vue都会执行)中执行如下代码:
import {decrypt} from '@/libs/AES'
import handleMenu from '@/router/handleMenu'
export default {
name: 'app',created () {
// 当this.$router.options.routes的长度为1,且本地缓存存在
菜单列表的时候才重新配置路由
if (this.$router.options.routes.length <= 1 && sessionStorage.getItem('subList')) {
let subList = JSON.parse(decrypt(sessionStorage.getItem('subList')))
let routes = handleMenu.mergeRoutes(subList)
this.$router.addRoutes(routes)
// this.$router不是响应式的,所以手动将路由元注入路由对象
this.$router.options.routes.push(routes)
}
}
}
这样即使刷新,也会重新配置路由了。
3、关于页面按钮级别控制,可以自定义一个指令,去做这件事情。因为我们已经权限列表放入了相应路由的Meta对象中,所以我们可以很方便的在每个页面回去到当前用户在当前页面所拥有的权限
参考官方文档自定义指令
结语
打完收工,得亏vue-router2中添加了addRoutes的方法,不然
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程之家。
原文链接:https://www.f2er.com/vue/32325.html