vue后台管理系统的菜单权限处理
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