Vue Router4 vue3 根据后端返回的路由数组动态匹配挂载路由

我们在做项目中经常遇到有后端返回的文件路径(比如order/orderList),然后前端根据获取的路由数组动态加载路由,今天我们就看看怎么样实现的吧!本项目vue版本vue3 vue-router4 pinia Vite 完成的

实现思路

  1. 在路由钩子里面判断是否首次进入系统(permission.ts)

  2. init为true说明已经获取过路由,就直接放行,init为false则向后台请求用户路由

  3. 获取路由

  4. 解析路由,存储权限

  5. 使用router的api,addRoute拼接路由

  6. 存储路由

  7. init改为true,路由初始化完成

  8. 放行路由

image-20230928140554125

###1 引入vue-router 设置静态路由 登陆,首页等。。。

import {createRouter, createWebHistory} from 'vue-router'
import Layout from '@/layout/index.vue'
//constantRoutes 静态路由 登陆,首页等。。。
export const constantRoutes = [
    {
        path: '/',//默认首页
        redirect: '/dashboard',
        hidden: true,
    },
    {
        path: "/dashboard",
        name: 'Dashboard',
        meta: {
            title: '首页',
            icon: "House",
        },
        component: Layout
    },
    {
        path: "/login",
        name: "Login",
        meta: {
            title: '登录'
        },
        component: () => import('@/views/user/login/index.vue'),
        hidden: true
    },
    {
        path: '/:pathMatch(.*)*',// 此写法解决动态路由页面刷新的 warning 警告
        component: () => import('@/views/user/error-page/404.vue'),
        hidden: true
    },
]
//动态路由 asyncRoutes
export const asyncRoutes = []

const router = createRouter({
    history: createWebHistory(),// HTML5的history模式
    routes: constantRoutes
})

export default router

2 获取后端路由数组,动态挂载路由permission.ts

import router from './router/index'
import { useUserStore } from '@/store/user'
import { usePermissionStore } from '@/store/permission'
import {getToken} from '@/utils/storage.ts'
import NProgress from 'nprogress'
import'nprogress/nprogress.css'
NProgress.configure({ showSpinner: false }) // NProgress Configuration
const whiteList = ['/login'] // 白名单
router.beforeEach(async (to) => {
    NProgress.start();
    document.title = `${to.meta.title} | vu3dny-admin`
    const hasToken = getToken('Access-Token')
    const userStore = useUserStore()
    const permissionStore = usePermissionStore()
    if (hasToken) {//判断token是否存在 存在即为已经登录
        if (to.path !== "/login") {
            if (userStore.init) { // 获取了动态路由 init一定true,就无需再次请求 直接放行
                return true
            }else {
                // init为false,一定没有获取动态路由,就跳转到获取动态路由的方法
                const result = await userStore.getInfo() //获取路由
                const accessRoutes = await permissionStore.generateRoutes(result.menus) 				//解析路由,存储路由
                // console.log(accessRoutes);
                // 动态挂载路由
                accessRoutes.forEach((route) => {
                    router.addRoute(route)
                })
                userStore.init = true//init改为true,路由初始化完成
                return { ...to, replace: true }// hack方法 确保addRoute已完成

            }
        }else {
            NProgress.done()
            return '/'
        }

    }else {
        // 白名单,直接放行
        if (whiteList.indexOf(to.path) > -1) return true
        // 非白名单,去登录
        else return '/login'
        NProgress.done()
    }
})
router.afterEach(() => {
    // finish progress bar
    NProgress.done()
})

3 递归解析路由 根据后端返回文件路径匹配路由

import.meta.glob的妙用:Vite是一个现代工具,你主要使用ES模块。而Vite用方便的工具扩展了全局import.meta 对象。例如,它添加了一个import.meta.glob 函数,允许你从路径中解析文件。比如后端返回的是oder/orderList 路由 需要前端匹配 你需要在views文件夹 新建一个order文件夹 然后文件夹新建一个orderList.vue

const modules = import.meta.glob('@/views/**/**.vue')

router的componentcomponent = modules[/src/views${e.url}]

当然 如果你用的是vue2 vueCli构建的vue项目 你可以用 require引入 import.meta.glob只适用于Vite

import {defineStore} from 'pinia'
import {constantRoutes} from '@/router'
import Layout from '@/layout/index.vue'
const modules = import.meta.glob('@/views/**/**.vue')
// console.log(modules);
export const filterAsyncRoutes = (routerList) => {
    //进行递归解析
    //routerList 后端获取的路由
    const res = []
    // console.log(testData);
    routerList.forEach(e => {
        // console.log(e.component);
        let e_new = {
            path: e.url,
            name: e.menuName,
            meta: {
                title: e.menuName,
                icon: e.icon
            },
             component: null

        }
        if (e.menuType === 'M') {
            e_new.component = Layout
        }else {
            // console.log("22222",e.url);
            e_new.component = modules[`/src/views${e.url}/index.vue`]
        }
        // console.log(e_new);
        if (e.children && e.children!=null) {
            const children = filterAsyncRoutes(e.children)
            // 保存权限
            e_new = { ...e_new, children: children }
        }

        res.push(e_new)
    })
    // console.vlog("111",res);
    return res
}

export const usePermissionStore = defineStore('permission', {
    id: 'permission', // id必填,且需要唯一
    state: () => {
        return {
            routes: [],//全部路由
            addRoutes: []//后端增加的路由
        }
    },
    actions: {
        generateRoutes(routes) {
            // console.log(routes);
            let routerList = JSON.parse(JSON.stringify(routes))
            // console.log(routerList);
            return new Promise((resolve) => {
                
                const accessedRoutes = filterAsyncRoutes(routerList)
                // console.log(accessedRoutes);
                this.addRoutes = accessedRoutes
                // console.log("111",accessedRoutes);
                this.routes = constantRoutes.concat(accessedRoutes)
                resolve(accessedRoutes)
            })

        }
    }
})
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值