vue-router之解決addRoutes使用遇到的坑
最近項(xiàng)目中使用了vue-router的addRoutes這個(gè)api,遇到了一個(gè)小坑,記錄總結(jié)一下。
場(chǎng)景復(fù)現(xiàn):
做前端開發(fā)的同學(xué),大多都遇到過(guò)這種需求:頁(yè)面菜單根據(jù)用戶權(quán)限動(dòng)態(tài)生成,一個(gè)常見的解決方案是:
前端初始化的時(shí)候,只掛載不需要權(quán)限路由,如登陸,注冊(cè)等頁(yè)面路由,然后等用戶登錄之后,后端返回當(dāng)前用戶的權(quán)限表,前端根據(jù)這個(gè)權(quán)限表遍歷前端路由表,動(dòng)態(tài)生成用戶權(quán)限路由,然后使用vue-router提供的addRoutes,將權(quán)限路由表動(dòng)態(tài)添加到路由實(shí)例中,整個(gè)過(guò)程大致如下:
// router.js 文件 // 需要用戶權(quán)限的路由表 const appRoutes = [ { path: '/dashboard', name: 'dashboard', component: () => import('...'), children: [ RouteConfig1, RouteConfig2, ... ] }, RouteConfig, ... ]; // 不需要用戶權(quán)限的路由表 const constantRoutes = [ { path: '/login', name: 'login', component: Login }, { path: '/register', name: 'register', component: Register }, ... ] // 初始化路由的時(shí)候,只掛載不需要用戶權(quán)限的路由表 const router = new VueRouter({ mode: 'history', base: process.env.BASE_URL, constantRoutes }); /** * * 假如后端返回的數(shù)據(jù)格式如下: * * { * status: 200, * message: 'successful', * data: { * user: {...}, * token: '...', * permisssion: [...] * } * } * * login.vue */ axios.post('/user/login',{username,password}) .then(res => { if (res.status === 200) { // 如果登錄成功,則需要遍歷生成用戶權(quán)限路由 // filterRoutes根據(jù)permission和router.js中定義的appRoutes生成動(dòng)態(tài)路由表 const routes = filterRoutes(permission); // 然后使用addRoutes將routes掛載到router中 router.addRoutes(routes); } else { ... } }) .catch(error => { ... })
寫到這里,貌似動(dòng)態(tài)生成路由的功能就好了,一切都perfect了,但問(wèn)題緊接著就來(lái)了,當(dāng)用戶登錄之后,我們點(diǎn)擊頁(yè)面上的退出按鈕退出當(dāng)前登錄,然后重新登錄,會(huì)發(fā)現(xiàn)瀏覽器console面板緊接著就報(bào)如下錯(cuò)誤:
納尼(⊙o⊙)?這是怎么回事呢,第二次登錄也正常登錄了,功能上似乎沒(méi)有什么問(wèn)題,但這個(gè)警告從哪里來(lái)的呢?對(duì)于一個(gè)重度強(qiáng)迫癥患者來(lái)說(shuō),任何警告和報(bào)錯(cuò)都是不允許出現(xiàn)的,哪怕功能上沒(méi)什么問(wèn)題。
捋一捋
這段警告的意思是說(shuō),以上的這幾個(gè)路由命名重復(fù),存在多個(gè)name相同的路由。那么為什么會(huì)有多個(gè)路由名稱相同的路由呢?
讓我們從頭捋一下這個(gè)錯(cuò)誤是怎么來(lái)的。首先第一次打開網(wǎng)站登錄的時(shí)候是沒(méi)有問(wèn)題的,只有當(dāng)我們退出登錄,重新登錄的時(shí)候,這段警告就來(lái)了。并且如果我們?cè)谥貜?fù)登錄之前刷新一下瀏覽器然后再登錄,這種警告就不會(huì)出現(xiàn)了,很神奇是不是?
分析一下上面的情景:首先這個(gè)警告只會(huì)在用戶重新登錄的時(shí)候出現(xiàn),登錄的時(shí)候我們做的唯一跟路由相關(guān)的事情就是動(dòng)態(tài)添加路由,所以問(wèn)題肯定出在 router.addRoutes(routes)這里,其次這里又分了兩種情況:有刷新和無(wú)刷新。在無(wú)刷新的情況下會(huì)報(bào)這個(gè)警告,有刷新就不會(huì)報(bào)這個(gè)警告。那么有刷新和無(wú)刷新有什么區(qū)別呢?
我們很容易就想到,當(dāng)頁(yè)面刷新的時(shí)候,Vue實(shí)例會(huì)重新初始化,Vue實(shí)例初始化的過(guò)程中,掛載在它上面的Vue-Router,Store等內(nèi)容也會(huì)重新初始化。而在不刷新的情況下,就不會(huì)重新初始化。
再想想,我們第一次登錄之后,通過(guò)addRoutes添加了權(quán)限路由routes到router上,假設(shè)我們這個(gè)權(quán)限r(nóng)outes中包括了dashboard,user,role三個(gè)路由,那么當(dāng)我們退出登錄,然后重新登錄的時(shí)候,由于同一個(gè)用戶登錄,后端返回的權(quán)限列表是一樣的,生成的動(dòng)態(tài)路由routes也是一樣的(即里面同樣包含了dashboard,user,role三個(gè)路由),那么此時(shí)再次添加這三個(gè)路由就導(dǎo)致router中掛載的routes重復(fù)。而在刷新的情況下,由于router重新初始化,只包含了初始化我們添加的不需要權(quán)限的路由,此時(shí)再次登錄,重新添加就不存在路由重復(fù)的問(wèn)題了。
通過(guò)以上的分析,我們搞清了問(wèn)題的來(lái)源,那么如何解決呢,很遺憾,vue-router并沒(méi)有刪除路由的api。根據(jù)以上的分析,我們很容易想到,通過(guò)強(qiáng)制刷新頁(yè)面的方式來(lái)重置router:即當(dāng)用戶退出登錄的時(shí)候,通過(guò)js強(qiáng)制刷新一下頁(yè)面。就可以解決問(wèn)題。這種方式雖然可以解決問(wèn)題,但顯得不是很優(yōu)雅,而且刷新頁(yè)面導(dǎo)致資源重新加載和頁(yè)面閃爍,體驗(yàn)也不是特別好。因此有沒(méi)有在不刷新的情況下解決問(wèn)題的辦法呢?
經(jīng)過(guò)一番搜索,終于找到了一種方法,即重置當(dāng)前router的match屬性:
router.js
// 定義一個(gè)函數(shù)來(lái)創(chuàng)建router export const createRouter = routes => new VueRouter({ mode: 'history', base: process.env.BASE_URL, routes }); // 在使用addRoutes的地方 // 重置當(dāng)前router的match = 初始router.match router.match = createRouter(constantRoutes).match; router.addRoutes(routes);
這樣就可以完美解決問(wèn)題了。
總結(jié):
整個(gè)解決的過(guò)程還是比較痛苦的,因?yàn)閷?shí)際中我的代碼是比較復(fù)雜的,并不像上面簡(jiǎn)化后那么簡(jiǎn)單。
整個(gè)addRoutes是在store.dispatch中完成,并且中間還夾雜著生成動(dòng)態(tài)路由,根據(jù)動(dòng)態(tài)路由再生成用戶菜單等一系列功能,干擾比較大,并且這個(gè)是源碼報(bào)警,不好定位,只能通過(guò)console和瀏覽器調(diào)試,一步步縮小報(bào)錯(cuò)范圍,最終找到問(wèn)題原因。
然后再通過(guò)google,以及搜索vue-router倉(cāng)庫(kù)的issue一步步找到解決方法。
所以想說(shuō),如果大家開發(fā)中遇到一些第三方依賴的問(wèn)題,可以去搜索官方倉(cāng)庫(kù)的issue,很好用的,很多問(wèn)題其實(shí)issue中都有答案。我是屢試不爽。
最后,一定要用google,百度,浪費(fèi)我好長(zhǎng)時(shí)間,啥都沒(méi)找到~
相關(guān)文章
多個(gè)Vue項(xiàng)目部署到服務(wù)器的步驟記錄
這篇文章主要給大家介紹了關(guān)于多個(gè)Vue項(xiàng)目部署到服務(wù)器的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10詳解vue項(xiàng)目打包后通過(guò)百度的BAE發(fā)布到網(wǎng)上的流程
這篇文章主要介紹了將vue的項(xiàng)目打包后通過(guò)百度的BAE發(fā)布到網(wǎng)上的流程,主要運(yùn)用的技術(shù)是vue+express+git+百度的應(yīng)用引擎BAE。需要的朋友可以參考下2018-03-03Vue?elementui如何實(shí)現(xiàn)表格selection的默認(rèn)勾選
這篇文章主要介紹了Vue?elementui如何實(shí)現(xiàn)表格selection的默認(rèn)勾選問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-06-06Vue監(jiān)聽數(shù)據(jù)對(duì)象變化源碼
這篇文章主要為大家詳細(xì)介紹了Vue監(jiān)聽數(shù)據(jù)對(duì)象變化的源碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03解決ElementUI中tooltip出現(xiàn)無(wú)法顯示的問(wèn)題
這篇文章主要介紹了解決ElementUI中tooltip出現(xiàn)無(wú)法顯示的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03vue實(shí)現(xiàn)todolist單頁(yè)面應(yīng)用
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)todolist單頁(yè)面應(yīng)用,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04