【转】vue 动态路由实现
方案一:
运用场景:系统根据登录账号的权限,动态加载左侧菜单; 后端直接返回的路由菜单数据
实现:
------------
*解决* :这里不可以全局修改属性值,在个别使用到的地方做css的修改。
2.2对一级菜单、二级菜单的component参数进行分别判断
*(InitRouters中的业务逻辑,根据实际情况进行修改)*
*根据缓存中的name值去循环判断(这里name和path在配置的时候是一致的)...实际情况判断...*
Tip: 路由陷入无线循环的情况:
运用场景:系统根据登录账号的权限,动态加载左侧菜单; 后端直接返回的路由菜单数据
实现:
1.获取的数据格式
- 一级目录component: ”components/main”
- 二级目录component: ”components/parentView”
- 目录下菜单component: "view/organization/user/user1.vue", //实际指向而定
- path值不可有重复指向
------------
2.将后端树转化为路由树( libs/util.js )
- 递归树
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
//动态路由 /** * @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 } |
- 处理树
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
/** * @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 } |
- 左侧菜单数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
///////////////动态路由 /** * @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 } |
- 后台管理踩过的坑
*解决* :这里不可以全局修改属性值,在个别使用到的地方做css的修改。
2.2对一级菜单、二级菜单的component参数进行分别判断
3.全局管理并缓存路由
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
// 获取用户相关信息 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在配置的时候是一致的)...实际情况判断...*
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
```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: 路由陷入无线循环的情况: