您好,登錄后才能下訂單哦!
怎么在vue中使用addRoutes實現動態路由?很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。
//初始路由: [{ path: '/login', name: 'login', component: (resolve) => require(['../views/common/404.vue'], resolve) }, { path: '/404', name: '404', component: (resolve) => require(['../views/common/404.vue'], resolve) }, { path: '*', redirect: '/404' }] //登錄邏輯 let vm = this; axios.get('/login', vm.user).then((res) => { let extendsRoutes = filterRoutes(res.menus); <!-- //假設得到的可用路由如下 [{ path: '/', name: '首頁', component: (resolve) => require(['../views/index.vue'], resolve), children: [{ path: '/menus', name: '菜單管理', component: (resolve) => require(['../views/menus.vue'], resolve) }, { path: '/resources', name: '資源管理', component: (resolve) => require(['../views/resources.vue'], resolve) }] }]--> //存菜單 sessionStorage.setItem('menus',JSON.stringify(extendsRoutes[0].children)); //動態添加路由 vm.$router.addRoutes(extendsRoutes); //跳轉到應用界面 vm.$router.push({path:'/'}); }) //首頁獲取菜單數據 this.menus = JSON.parse(sessionStorage.getItem('menus')); //用此數據循環菜單 ..
目前為止看上去一切順利,然而前方有坑。
動態路由的坑
第一個坑是,如果你將這套邏輯實現之后會發現打開應用看到的第一個頁面是404,這是因為啟動服務后將默認打開首頁'/‘,然而初始路由中沒有這個路徑,因此根據路由規則跳轉到了404。我們希望結果當然是跳轉到'/login',因此需要對這種情況做判斷,在用戶登錄之前所有請求都要指向'/login',這個判斷可以在before鉤子里做也可以在根組件里做,建議做在根組件的created回調里,核心代碼大概這樣:
let isLogin = sessionStorage.getItem('user'); if(!isLogin){ return this.$router.push({path:'/login'}); }
這時候已經可以順利登錄了,登錄后很快就會發現第二個坑,手動刷新頁面又會跳到404,這是因為刷新會導致Vue重新實例化,路由也恢復到了初始路由,于是當前路徑又被重定向到了404,這個問題的根源是可用路由沒有實現持久化,那么可以通過將路由數據存sessionStorage來解決,實例化之前如果檢測到本地路由就直接合并路由,像這樣:
//檢測本地路由 let localRoutes = sessionStorage.getItem('routes'); if(localRoutes){ router.addRoutes(JSON.parse(localRoutes)); } //實例化 new Vue({ el: '#app', router, render: h => h(App) });
理論上可以,但實際操作要遠比上述代碼復雜,因為存在本地的只能是權限數據而不是真實路由,路由在存、取之前都要先根據權限匹配獲得,過程還是挺繁瑣的,而且必須依賴sessionStorage這種持久存儲,沒有其他方法。問題就出在這個sessionStorage上,原則上權限只能在內存變量中流轉,不能直接暴露到用戶可操作的地方,試想只要用戶手動修改了sessionStorage里的權限,再刷新一下頁面就能突破前端路由控制了,非常的不靠譜。
改進方案
既然不能存本地,那就每次刷新都重新從服務端獲取,所以改進后的方案是本地存用戶token,每次刷新要憑token從服務端重新獲取用戶信息和權限,然后動態更新路由,獲取權限操作可以跟登錄檢測一起放在根組件的created回調中進行,確保訪問任何路徑都會先執行這一步,但因為獲取權限是異步操作,在此之前仍然會經過應用初始化,所以還是會遇到404的問題,為此我們只需做一個小調整,將不匹配路徑(‘*')跳404的路由從初始路由中移除,動態更新路由時再把這個配置加進去,如下:
let userPath = ...//我們的動態路由 //注入時拼接404處理路由 this.$router.addRoutes(userPath.concat([{ path: '*', redirect: '/404' }]));
這樣就解決了刷新問題,后面還有幾個小問題就簡單了。
首先是菜單,之前通過$router.options.routes訪問路由數據實現動態菜單,但這個數據不是響應式的,無法追蹤動態路由的變化,因此我們需要將得到的導航菜單數據存到sessionStorage或Vuex里實現數據共享。
資源權限控制也受到很大的影響,實現較為細致的權限控制需要一個自定義權限驗證指令和一個全局驗證方法,之前的方案里權限是在Vue實例化之前獲取的,所以可以很方便的拿到權限后實現驗證方法,然后用驗證方法實現自定義指令,再將方法全局混合進Vue,然后實例化,這樣實例中的 所有組件都可以使用自定義指令和驗證方法;但現在的方案是先實例化再獲取權限,實例化之前根本沒有權限數據,所以自定義指無法實現,等拿到權限后實現了驗證方法,卻無法再全局混合了。
這個問題最后也解決了,但解決方案就徹底的”有辱斯文”了,首先是全局方法的實現,直接這么做:
Vue.prototype.has = function(){ ... }
使用方式跟全局混合的方法完全一樣。
自定義指令的實現本來很頭疼,因為全局指令只能在實例化之前實現,但那時候又確實沒有權限,不過既然驗證方法這么做的話,指令倒是也順便解決了,像這樣:
//權限指令 Vue.directive('has', { bind: function(el, binding) { if (!Vue.prototype.has(binding.value)) { el.parentNode.removeChild(el); } } });
看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。