【轉】vue 動態路由實現


方案一:
運用場景:系統根據登錄賬號的權限,動態加載左側菜單; 后端直接返回的路由菜單數據

實現:

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
}
 

  • 后台管理踩過的坑
2.1菜單配置使用的是矢量圖標庫里面的圖標所以要加上和iview圖標font-family屬性不一致;ivew-admin里面都是默認的font-family:'Ionicons'=>轉成 font-family:'iconfont'
  *解決* :這里不可以全局修改屬性值,在個別使用到的地方做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: 路由陷入無線循環的情況:


 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM