vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > vue3动态路由+菜单栏

vue3动态路由+菜单栏的实现示例

作者:汤达人

在后台管理系统,可以根据登录用户的不同返回不同路由,页面也会根据这些路由生成对应的菜单,本文主要介绍了vue3动态路由+菜单栏的实现示例,感兴趣的可以了解一下

动态路由

这里用vue3和vite来实现动态路由,点击这里查看效果 源码

使用场景

在后台管理系统,可以根据登录用户的不同返回不同路由,页面也会根据这些路由生成对应的菜单。这样通过服务器就能控制一个用户可以访问的内容了。
比如管理员可以看到服务器日志,可以进行系统设置,普通用户就访问不了这些页面。

步骤

定义基础路由表
有一些路由不需要登录也能访问的,比如login和404页面,这些路由要提前在写好并加入到router中。
编写路由组件
所有的路由组件都要提前写好放到/views目录下
添加路由
定义addRoute()方法,在登录后获取服务器路由通过这个方法添加路由
生成菜单
路由的meta字段可以添加一些菜单相关的信息,比如菜单名、icon、排序之类的。遍历路由列表,根据meta的信息就能生成对应的菜单了

代码

服务器路由数据

这里模拟服务器返回的数据,为了方便只写了一条路由,看源码有更多示例。
meta的数据是自己定的,一定要跟后端对接好。

[  
    {  
        path: '/user',  
        component: 'DEFAULT_LAYOUT',  
        meta: {menuName: '用户', order: 1},  
        children: [  
            {  
                path: 'info',  
                name: 'userInfo',  
                component: 'user/info',  
                meta: {menuName: '个人中心'}  
            }  
        ]  
    }  
]  

注意

添加路由

假设现在登录成功,开始调用addRoute()方法添加路由,这个方法根据情况放在自己需要的地方,这里为了演示都放在一起了。

// /components/layout.vue  
import { ref } from 'vue'  
import { useRouter } from 'vue-router'  
// 这个布局组件需要自己提前定义好  
import DEFAULT_LAYOUT from '@/components/layout.vue'  
  
const server_route = ref([])  
  
const addRoute = async () => {  
    // 如果本地没有路由信息,就从服务器获取  
    if (!server_route.value.length) {  
        // 这里模拟从服务器获取数据,实际需要从后端获取数据  
        const { default: routes = [] } = await import('@/router/server_route')  
        server_route.value = routes  
    }  

    // 把路由表的component字段转成真实的路由  
    server_route.value.map((_route) => {  
        if (_route.component === 'DEFAULT_LAYOUT') {  
            _route.component = DEFAULT_LAYOUT  
        }  
        const children = _route.children  
        // 根据字符串动态导入路由组件  
        if (Array.isArray(children) && children?.length > 0) {  
            children.map((childRoute) => {  
                const path = childRoute.component.split('/')  
                if (path.length === 1) {  
                    childRoute.component = () => import(`@/views/${path}.vue`)  
                } else {  
                    childRoute.component = () => import(`@/views/${path[0]}/${path[1]}.vue`)  
                }  
            })  
        }  
    })  
  
    // 排序  
    server_route.value.sort((a, b) => (a?.meta?.order ?? 0) - (b?.meta?.order ?? 0))  

    // 循环添加路由  
    server_route.value.map((route) => router.addRoute(route))  
}  

从服务器获取到的数据会保存到server_route里面,实际开发应该保存到本地localStorage,否则刷新所有路由消失。
获取到数据还不能用,因为component字段还是字符串,要转成懒加载的形式导入组件才行。

// 把路由表的component字段转成真实的路由  
server_route.value.map((_route) => {  
    if (_route.component === 'DEFAULT_LAYOUT') {  
        // 设置布局组件,可以为项目设置多个布局,服务器只需要修改这里,前端就能显示多种布局了  
        _route.component = DEFAULT_LAYOUT  
    }  
    const children = _route.children  
    // 根据字符串动态导入路由组件  
    if (Array.isArray(children) && children?.length > 0) {  
        children.map((childRoute) => {  
        const path = childRoute.component.split('/')  
        // 用vite提供的动态导入功能,根据字符串从views目录下导入组件  
        // 参考:https://cn.vitejs.dev/guide/features.html#dynamic-import  
        if (path.length === 1) {  
            // 如果是单个vue文件  
            childRoute.component = () => import(`@/views/${path[0]}.vue`)  
        } else {  
            // 否则就是一个目录  
            childRoute.component = () => import(`@/views/${path[0]}/${path[1]}.vue`)  
        }  
        })  
    }  
}) 

因为父组件的布局组件比较少,一般不用做懒加载全部导入进来,根据字符串选择对应的布局就行了。

子组件需要动态的导入。vite提供了根据变量动态导入模块的方法。

如果component: 'user/info'

// 路径必须以绝对路径,相对路径或@开头,文件名结尾,vite官网有说明  
// 不符合的话导入报错  
childRoute.component = () => import(`@/views/${path[0]}/${path[1]}.vue`)  

如果component: 'welcome'

childRoute.component = () => import(`@/views/${path[0]}.vue`)  

上面的代码默认子路由下面没有子路由了,如果有很多级路由的话,需要做更多的判断。

经过转换已经把component转成真正的组件了,转换后的server_route

import DEFAULT_LAYOUT from '@/components/layout.vue'  
  
server_route.value = [  
    {  
        path: '/user',  
        component: DEFAULT_LAYOUT,  
        meta: {menuName: '用户', order: 1},  
        children: [  
            {  
                path: 'info',  
                name: 'userInfo',  
                component: () => import('@/views/user/info.vue'),  
                meta: {menuName: '个人中心'}  
            }  
        ]  
    }  
]  

这样再排序一下然后就可以直接添加到router里面了

import { useRouter } from 'vue-router'  
const router = useRouter()  
// 排序  
server_route.value.sort((a, b) => (a?.meta?.order ?? 0) - (b?.meta?.order ?? 0))  
// 遍历转换好的路由表,添加路由  
server_route.value.map((_route) => router.addRoute(_route))  

生成菜单

有了路由数据,下面可以生成菜单了,这里只对server_route服务器返回的数据生成菜单,本地定义的路由不会添加到菜单里面

<!-- /components/layout.vue -->  
<template>  
    <div>  
        <nav>  
            <h1>菜单栏</h1>  

            <div style="display: flex; gap: 50px; align-items: flex-end;">  
            <template v-for="menu in server_route">  
                <!-- 显示多级菜单-->  
                <div v-if="!menu.meta.single">  
                    <h5>{{ menu.meta.menuName }}</h5>  
                    <button  
                        v-for="child in menu.children"  
                        @click="router.push({name: child.name})">  
                        {{ child.meta.menuName }}  
                    </button>  
                </div>  

                <!-- 只显示一级菜单-->  
                <div v-else>  
                    <button @click="router.push({name: menu.children[0].name})">{{ menu.children[0].meta.menuName }}</button>  
                </div>  
            </template>  
            </div>  
        </nav>  

        <hr>  
        <button v-show="needAddRoutes" @click="login">模拟登录获取路由</button>  

        <main>  
            <router-view />  
        </main>  
    </div>  
</template>  

上面的代码只是演示,实际开发应该定义一个单独的layout-aside组件专门渲染菜单。

总结

动态添加路由只要提前定义好服务器数据,约定好格式,做起来还是很简单的。只要能根据component字段正确的导入组件就没什么大问题,
不过这只是一个简单的示例,实际开发还是有很多情况要处理的。

到此这篇关于vue3动态路由+菜单栏的实现示例的文章就介绍到这了,更多相关vue3动态路由+菜单栏内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文