方案一:
运用场景:系统根据登录账号的权限,动态加载左侧菜单; 后端直接返回的路由菜单数据
实现:
1.获取的数据格式
- 一级目录component: ”components/main”
- 二级目录component: ”components/parentView”
- 目录下菜单component: "view/organization/user/user1.vue", //实际指向而定
- path值不可有重复指向
------------
2.将后端树转化为路由树( libs/util.js )
//动态路由
/**
* @description 将后端菜单树转换为路由树 递归树
* @param {Array} menus
* @returns {Array}
*/
export const backendMenusToRouters = (menus) => {
let routers = []
forEach(menus, (menu) => {
// 将后端数据转换成路由数据
let route = backendMenuToRoute(menu)
// 如果后端数据有下级,则递归处理下级
if (menu.children && menu.children.length !== 0 && menu.name != "") {
route.children = backendMenusToRouters(menu.children)
}
routers.push(route)
})
// console.log(routers)
return routers
}
/**
* @description 将后端菜单转换为路由 处理树
* @param {Object} menu
* @returns {Object}
*/
const backendMenuToRoute = (menu) => {
// 具体内容根据自己的数据结构来定,这里需要注意的一点是
// 原先routers写法是component: () => import('@/view/error-page/404.vue')
// 经过json数据转换,这里会丢失,所以需要按照上面提过的做转换,下面只写了核心点,其他自行处理
let route = Object.assign({}, menu)
// route.component = () => import(`/* webpackChunkName: ${menu.title} */'@/${menu.component}'`)\
// 菜单配置的时候都是矢量图标库里面的图标所以要加上iconfont,ivew-admin里面都是默认的font-family:'Ionicons'=>转成 font-family:'iconfont'
if(menu.meta){
route.meta.icon = `iconfont ${menu.meta.icon}`
} //矢量图标转划
if(menu.component == "components/main"){
route.component = Main; //一级菜单判断
}
else if(menu.component == "components/parentView"){
route.component = parentView; //二级菜单判断
}
else{
route.component = () => import(`@/${menu.component}`);
}
return route
}
///////////////动态路由
/**
* @param {Array} list 通过路由列表得到菜单列表
* @param access
* @returns {Array}
*/
export const getUserMenuByRouter = (list) => {
// console.log(list)
let res = []
forEach(list, item => {
//meta没配置,或者配置了,但hideInMenu=false
if (!item.meta || (item.meta && !item.meta.hideInMenu)) {
let obj = {
icon: (item.meta && item.meta.icon) || '',
name: item.name,
meta: item.meta
}
//有下级子元素或者showAlways=true并且还有权限访问,继续递归处理下级(item.meta && !item.meta.showAlways)
if ((hasChild(item))) {
obj.children = getUserMenuByRouter(item.children)
}
//如果配置了href,设置href
if (item.meta && item.meta.href) obj.href = `${baseUrl}`+`${item.meta.href}`
//加入
res.push(obj)
}
})
return res
}
2.1菜单配置使用的是矢量图标库里面的图标所以要加上和iview图标font-family属性不一致;ivew-admin里面都是默认的font-family:'Ionicons'=>转成 font-family:'iconfont'
*解决* :这里不可以全局修改属性值,在个别使用到的地方做css的修改。
2.2对一级菜单、二级菜单的component参数进行分别判断
3.全局管理并缓存路由
// 获取用户相关信息
getUserInfo ({ state, commit }) {
let paramer ={
token:state.token,
refresData:false,
}
// console.log(state.token)
return new Promise((resolve, reject) => {
try {
getUserInfo(paramer).then(res => {
// console.log(res)
const data = res.data.result
// console.log("菜单",JSON.stringify(data.menuRoutes))
// commit('setAvatar', data.avatar) //头像
commit('setUserName', data.loginName)
commit('setUserInfo', data)
commit('setAccess', data.roleInfoDto.roleName) //权限 角色
commit('setHasGetInfo', true)
let routers = backendMenusToRouters(data.menuRoutes)
console.log(routers)
commit('setRouters', routers)
commit('setHasGetRouter', true)
localStorage.setItem("getInfo", true);
localStorage.setItem("router", JSON.stringify(data.menuRoutes));
resolve(data)
}).catch(err => {
reject(err)
})
} catch (error) {
reject(error)
}
})
},
4.重置路由,在最后添加404页面路径
获取到缓存里的数据,在until.js中的方法转化后得到路由数据,最后加上404页面路径并重置路由
*(InitRouters中的业务逻辑,根据实际情况进行修改)*
- 除了考虑正常跳转,浏览器刷新,不存在的页面地址都需考虑
- Tip:浏览器刷新后,路由中的name值可能会消失
*根据缓存中的name值去循环判断(这里name和path在配置的时候是一致的)...实际情况判断...*
```html
// version2
const initRouters = (to, next) => {
// 在路由最后动态添加404, path:"*"
let rou = JSON.parse(localStorage.getItem("router"));
let routers = backendMenusToRouters(rou);
routers.push({
path: '*',
name: 'error_404',
meta: {
hideInMenu: true
},
component: () => import('@/view/error-page/404.vue')
})
router.addRoutes(routers);
let arr = [];
let names2 = [];
let names = getAllNames(rou,arr);
names2= names.concat(["login","home","error_401","error_500"]);
console.log(names2)
let path = to.path;
let path1 = path.substr(path.lastIndexOf('/') + 1);
console.log(path1)
console.log(names2.includes(path1))
if (to.matched.length > 0 ) {
next()
}
else if (to.name !== null && to.matched.length === 0) {
next({
name: 'error_404'
})
return
}
else {
next({
name: path1
})
}
}
Tip: 路由陷入无线循环的情况: