最近項目中使用了vue-router的addRoutes這個api,遇到了一個小坑,記錄總結一下。javascript
場景復現:
作前端開發的同窗,大多都遇到過這種需求:頁面菜單根據用戶權限動態生成,一個常見的解決方案是:前端
前端初始化的時候,只掛載不須要權限路由,如登錄,註冊等頁面路由,而後等用戶登陸以後,後端返回當前用戶的權限表,前端根據這個權限表遍歷前端路由表,動態生成用戶權限路由,而後使用vue-router提供的addRoutes,將權限路由表動態添加到路由實例中,整個過程大體以下:vue
// router.js 文件
// 須要用戶權限的路由表
const appRoutes = [
{
path: '/dashboard',
name: 'dashboard',
component: () => import('...'),
children: [
RouteConfig1,
RouteConfig2,
...
]
},
RouteConfig,
...
];
// 不須要用戶權限的路由表
const constantRoutes = [
{
path: '/login',
name: 'login',
component: Login
},
{
path: '/register',
name: 'register',
component: Register
},
...
]
// 初始化路由的時候,只掛載不須要用戶權限的路由表
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
constantRoutes
});
/** * * 假如後端返回的數據格式以下: * * { * status: 200, * message: 'successful', * data: { * user: {...}, * token: '...', * permisssion: [...] * } * } * * login.vue */
axios.post('/user/login',{username,password})
.then(res => {
if (res.status === 200) {
// 若是登陸成功,則須要遍歷生成用戶權限路由
// filterRoutes根據permission和router.js中定義的appRoutes生成動態路由表
const routes = filterRoutes(permission);
// 而後使用addRoutes將routes掛載到router中
router.addRoutes(routes);
} else {
...
}
})
.catch(error => { ... })
複製代碼
寫到這裏,貌似動態生成路由的功能就行了,一切都perfect了,但問題緊接着就來了,當用戶登陸以後,咱們點擊頁面上的退出按鈕退出當前登陸,而後從新登陸,會發現瀏覽器console面板緊接着就報以下錯誤:
java
納尼(⊙o⊙)?這是怎麼回事呢,第二次登陸也正常登陸了,功能上彷佛沒有什麼問題,但這個警告從哪裏來的呢?對於一個重度強迫症患者來講,任何警告和報錯都是不容許出現的,哪怕功能上沒什麼問題。ios
捋一捋git
這段警告的意思是說,以上的這幾個路由命名重複,存在多個name相同的路由。那麼爲何會有多個路由名稱相同的路由呢?github
讓咱們從頭捋一下這個錯誤是怎麼來的。首先第一次打開網站登陸的時候是沒有問題的,只有當咱們退出登陸,從新登陸的時候,這段警告就來了。而且若是咱們在重複登陸以前刷新一下瀏覽器而後再登陸,這種警告就不會出現了,很神奇是否是?vue-router
分析一下上面的情景:首先這個警告只會在用戶從新登陸的時候出現,登陸的時候咱們作的惟一跟路由相關的事情就是動態添加路由,因此問題確定出在 router.addRoutes(routes)
這裏,其次這裏又分了兩種狀況:有刷新和無刷新。在無刷新的狀況下會報這個警告,有刷新就不會報這個警告。那麼有刷新和無刷新有什麼區別呢?axios
咱們很容易就想到,當頁面刷新的時候,Vue實例會從新初始化,Vue實例初始化的過程當中,掛載在它上面的Vue-Router,Store等內容也會從新初始化。而在不刷新的狀況下,就不會從新初始化。後端
再想一想,咱們第一次登陸以後,經過addRoutes添加了權限路由routes到router上,假設咱們這個權限routes中包括了dashboard,user,role三個路由,那麼當咱們退出登陸,而後從新登陸的時候,因爲同一個用戶登陸,後端返回的權限列表是同樣的,生成的動態路由routes也是同樣的(即裏面一樣包含了dashboard,user,role三個路由),那麼此時再次添加這三個路由就致使router中掛載的routes重複。而在刷新的狀況下,因爲router從新初始化,只包含了初始化咱們添加的不須要權限的路由,此時再次登陸,從新添加就不存在路由重複的問題了。
經過以上的分析,咱們搞清了問題的來源,那麼如何解決呢,很遺憾,vue-router並無刪除路由的api。根據以上的分析,咱們很容易想到,經過強制刷新頁面的方式來重置router:即當用戶退出登陸的時候,經過js強制刷新一下頁面。就能夠解決問題。這種方式雖然能夠解決問題,但顯得不是很優雅,並且刷新頁面致使資源從新加載和頁面閃爍,體驗也不是特別好。所以有沒有在不刷新的狀況下解決問題的辦法呢?
通過一番搜索,終於找到了一種方法,即重置當前router的match屬性:
router.js
// 定義一個函數來建立router
export const createRouter = routes => new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
});
// 在使用addRoutes的地方
// 重置當前router的match = 初始router.match
router.match = createRouter(constantRoutes).match;
router.addRoutes(routes);
複製代碼
這樣就能夠完美解決問題了。
總結:
整個解決的過程仍是比較痛苦的,由於實際中個人代碼是比較複雜的,並不像上面簡化後那麼簡單。整個addRoutes是在store.dispatch中完成,而且中間還夾雜着生成動態路由,根據動態路由再生成用戶菜單等一系列功能,干擾比較大,而且這個是源碼報警,很差定位,只能經過console和瀏覽器調試,一步步縮小報錯範圍,最終找到問題緣由。而後再經過google,以及搜索vue-router倉庫的issue一步步找到解決方法。因此想說,若是你們開發中遇到一些第三方依賴的問題,能夠去搜索官方倉庫的issue,很好用的,不少問題其實issue中都有答案。我是屢試不爽。最後,必定要用google,垃圾百度,浪費我好長時間,啥都沒找到