背景
-
后端返回路由这个场景非常常见,用的很多,也用了很多次
-
特此记录一下
路由配置
1、默认路由部分
import Vue from 'vue'
import VueRouter from 'vue-router'
import store from '@/store'
Vue.use(VueRouter)
// 解决push重复路由报错
const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(location) {
return originalPush.call(this, location).catch((err) => err)
}
const routes = [
{
path: '/',
name: 'root',
menuName: 'Layout',
redirect: '/home',
},
{
path: '/home',
name: 'home',
menuName: 'Layout',
component: () => import(/* webpackChunkName: "home" */ '@/views/Home'),
},
{
path: '/login',
name: 'login',
component: () => import(/* webpackChunkName: "login" */ '../views/Login'),
},
// {
// path: '*',
// name: 'ERROR404',
// component: () => import('@/views/Error'),
// },
]
const router = new VueRouter({
routes,
})
router.beforeEach(async (to, from, next) => {
const token = store.state.user.token
if (token) {
if (to.path === '/login') {
store.dispatch('resetAll')//清空vuex数据
next()
} else {
next()
}
} else {
store.dispatch('resetAll')//清空vuex数据
if (to.path === '/login') {
next()
} else {
next('/login')
}
}
})
export default router
- 这个时候只有只有三个路由,/home需要token才能访问,,没登录的情况下只能看见登录页面
2、登录后,从接口获取菜单路由信息
// menuPath.js
const develop = process.env.NODE_ENV === 'development'
const product = process.env.NODE_ENV === 'production'
const menuPath = new Map([
['/', () => import('@/views/Home/index.vue')],
['/user', () => import('@/views/UserManage/index.vue')],
['/log', () => import('@/views/Log/index.vue')],
['/role', () => import('@/views/RoleManage/index.vue')],
['/menu', () => import('@/views/MenuManage/index.vue')],
['/404', () => import('@/views/Error/index.vue')],
])
export default menuPath
async getMenuList() {
const params = {
menuName: '',
status: 0, //0正常 1停用
}
const res = await this.$api.getMenuList(params)
if (res.code != 0) return
const menuList = this.getDyMenuList(res.data)
menuList.forEach((item) => {
// 这里将处理后的菜单添加到路由里面去
this.$router.addRoute(item)
})
},
getDyMenuList(menu) {
const result = []
const handler = (menu, result) => {
menu.forEach((v) => {
const obj = {
path: v?.path ?? '',
icon: '',
menuId: v?.menuId ?? '',
name: v.menuName ?? '',
menuName: v?.menuName ?? '',
// 这个位置是将接口返回的菜单路径与我们写的页面连接起来
component: menuPath.has(v.path) ? menuPath.get(v.path) : menuPath.get('/404'),
children: [],
}
if (v.root) {
obj.path = '/'
obj.redirect = v.children[0].path
}
result.push(obj)
if (v.children && v.children.length) {
handler(v.children, obj.children)
}
})
}
handler(menu, result)
return result
},
-
这个时候已经将菜单加到路由里面了,我们可以更改url路径访问对应的页面
-
但是,整个流程还没弄完,因为这个时候一刷新页面,就会出现空白的情况,这是因为我们添加的动态路由是存在内存里面的。
-
我们需要在路由拦截这个位置做一些处理
const getMenu = (menuList) => {
menuList.forEach((item) => {
item.component = menuPath.get(item.path)
if (item.children && item.children.length > 0) {
getMenu(item.children)
}
})
}
const hasRouter = (to) => {
if (to.matched.length === 0) {
const menuList = JSON.parse(JSON.stringify(store.state.user.menuList))
getMenu(menuList)
router.addRoute(menuList[0])
return false
}
return true
}
router.beforeEach(async (to, from, next) => {
const token = store.state.user.token
if (token) {
if (to.path === '/login') {
store.dispatch('resetAll')
next()
} else {
// 在这个位置做处理,页面刷新后,内存清空,需要重新添加路由
// next({ ...to, replace: true }),这个也很重要,参考 https://blog.csdn.net/qq_41912398/article/details/109231418
const state = hasRouter(to)
state ? next() : next({ ...to, replace: true })
}
} else {
store.dispatch('resetAll')
if (to.path === '/login') {
next()
} else {
next('/login')
}
}
})
export default router
3、至此,动态路由添加才算是完成了