1.
在首次請求登錄接口的時候,由后端返回相應的角色權限,再根據這個進行動態路由生成。
自己根據角色創建不同的路由表,然后在登錄時拿 到不同的角色標記,來引入對應的路由表。
2.把路由表存儲在vuex中,右側菜單通過直接引入vuex存的路由表進行渲染。
通過接口返回的角色權限,根據角色來動態的通過router.addRoutes(),添加不同的路由。
3.在路由守衛router.beforeEach中進行判斷
const hasRoles = store.getters.roles && store.getters.roles.length > 0 if (hasRoles) { next() } else { try { // get user info // note: roles must be a object array! such as: ['admin'] or ,['developer','editor'] const { roles } = await store.dispatch('user/getInfo') // generate accessible routes map based on roles const accessRoutes = await store.dispatch('permission/generateRoutes', roles) // dynamically add accessible routes router.addRoutes(accessRoutes) // hack method to ensure that addRoutes is complete // set the replace: true, so the navigation will not leave a history record next({ ...to, replace: true }) } catch (error) { // remove token and go to login page to re-login await store.dispatch('user/resetToken') Message.error(error || 'Has Error') next(`/login?redirect=${to.path}`) NProgress.done() } }
正以為如此很多人在使用動態添加路由addRoutes()會遇到下面的情況:
在addRoutes()之后第一次訪問被添加的路由會白屏,這是因為剛剛addRoutes()就立刻訪問被添加的路由,然而此時addRoutes()沒有執行結束,因而找不到剛剛被添加的路由導致白屏。因此需要從新訪問一次路由才行。
該如何解決這個問題 ?
此時就要使用next({ ...to, replace: true })來確保addRoutes()時動態添加的路由已經被完全加載上去。
next({ ...to, replace: true })中的replace: true只是一個設置信息,告訴VUE本次操作后,不能通過瀏覽器后退按鈕,返回前一個路由。
因此next({ ...to, replace: true })可以寫成next({ ...to }),不過你應該不希望用戶在addRoutes()還沒有完成的時候,可以點擊瀏覽器回退按鈕搞事情吧。
其實next({ ...to })的執行很簡單,它會判斷:
如果參數to不能找到對應的路由的話,就再執行一次beforeEach((to, from, next)直到其中的next({ ...to})能找到對應的路由為止。
也就是說此時addRoutes()已經完成啦,找到對應的路由之后,接下來將執行前往對應路由的beforeEach((to, from, next) ,因此需要用代碼來判斷這一次是否就是前往對應路由的beforeEach((to, from, next),如果是,就執行next()放行。
如果守衛中沒有正確的放行出口的話,會一直next({ ...to})進入死循環 !!!
因此你還需要確保在當addRoutes()已經完成時,所執行到的這一次beforeEach((to, from, next)中有一個正確的next()方向出口。
因此想實現動態添加路由的操作的話,代碼應該是這樣的:
router.beforeEach((to, from, next) => { const token = sessionStorage.getItem('access_token') // 存在 token 說明已經登錄 if (token) { // 登錄過就不能訪問登錄界面,需要中斷這一次路由守衛,執行下一次路由守衛,並且下一次守衛的to是主頁' if (to.path === '/login') { next({ path: '/' }) } // 保存在store中路由不為空則放行 (如果執行了刷新操作,則 store 里的路由為空,此時需要重新添加路由) if (store.getters.getRoutes.length || to.name != null) { //放行 next() } else { // 將路由添加到 store 中,用來標記已添加動態路由 store.commit('ADD_ROUTER', '需要添加的路由') router.addRoutes('需要添加的路由') // 如果 addRoutes 並未完成,路由守衛會一層一層的執行執行,直到 addRoutes 完成,找到對應的路由 next({ ...to, replace: true }) } } else { // 未登錄時,注意 :在這里也許你的項目不只有 logon 不需要登錄 ,register 等其他不需要登錄的頁面也需要處理 if (to.path !== '/logon') { next({ path: '/logon' }) } else { next() } }
4.在路由文件中實例化了路由,會導致在vuex中獲取不到路由列表,打印undefined。最后通過(路由懶加載)路由文件中的component引入方式改為
5. 退出或切換角色時需要路由重置,防止因為router.addroutes()導致路由重復添加
router/index.js 文件
const createRouter = () => new Router({ // mode: 'history', // require service support scrollBehavior: () => ({ y: 0 }), routes: constantRoutes }) const router = createRouter() // Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
// 退出或切換角色時需要路由重置,防止因為router.addroutes()導致路由重復添加
export function resetRouter() { //重置方法 const newRouter = createRouter() router.matcher = newRouter.matcher // reset router }
6.vuex中批量引入所有的modules文件
//webpack批量引入文件
const modulesFiles = require.context('./modules', true, /\.js$/) // you do not need `import app from './modules/app'` // it will auto require all vuex module from modules file const modules = modulesFiles.keys().reduce((modules, modulePath) => { // set './app.js' => 'app' const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1') const value = modulesFiles(modulePath) modules[moduleName] = value.default return modules }, {}) const store = new Vuex.Store({ modules, getters })
7. vuex namespaced的作用以及使用方式
vuex中的store分模塊管理,需要在store的index.js中引入各個模塊,為了解決不同模塊命名沖突的問題,將不同模塊的namespaced:true,之后在不同頁面中引入getter、actions、mutations時,需要加上所屬的模塊名
const state = { token: getToken(), name: '', avatar: '', introduction: '', roles: [] } const mutations = { SET_TOKEN: (state, token) => { state.token = token }, } const actions = { // user login login({ commit }, userInfo) { const { username, password } = userInfo return new Promise((resolve, reject) => { login({ username: username.trim(), password: password }).then(response => { const { data } = response commit('SET_TOKEN', data.token) setToken(data.token) resolve() }).catch(error => { reject(error) }) }) }, } export default { namespaced: true, state, mutations, actions }
8.router.addRoutes添加的動態路由,刷新頁面后跳到404頁面
在使用addRoutes之前我就定義了,通配符 * 跳轉到404頁面如下圖: 這就是問題所在。
解決方法是 不要再路由中添加404頁面 在addRoutes里進行拼接 (通配符 * 跳轉到404頁面的路由)
在beforeEach中打印 to發現是404 打印from顯示是/
當頁面一刷新 addRoutes 還沒有添加上 路由就開始跳轉了 所以找不到路由就跳轉到404頁面了
轉:https://blog.csdn.net/qq_37121488/article/details/88287066
轉:https://blog.csdn.net/qq_41912398/article/details/109231418