vue2 动态路由

174 阅读2分钟

背景

  • 后端返回路由这个场景非常常见,用的很多,也用了很多次

  • 特此记录一下

路由配置

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、至此,动态路由添加才算是完成了

参考文章