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

教程下载地址: 网赚博客https://www.piaodoo.com/创业项目排行榜前十名https://www.piaodoo.com/


动态路由

这里用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: '个人中心'}  
            }  
        ]  
    }  
]  

注意

  • 只支持二级路由,也就是子路由下不能再有子路由
  • 每个一级路由至少有一个子路由,即使你只想展示一个菜单。因为父路由需要显示布局组件,子路由才是真正显示内容的地方。
  • component: 'DEFAULT_LAYOUT'表示这个路由要使用的布局组件,需要提前定义好。
  • meta: {menuName: '用户', order: 1}menuName表示这个菜单的名称,order表示菜单的排序,还可以添加其他内容,比如
  • 只有一个子路由不想生成二级菜单,就可以设置single: true
  • 子路由的name,必须设置这个字段,而且整个路由中不能重复,点击一个菜单时需要用它来导航
  • 子路由的component表示路由组件的位置,需要提前在/views目录下把所有路由组件都写好。比如这里的user/info
  • 实际会导入import('@/views/user/info.vue')。注意:路径之间必须用/隔开
  • meta: {menuName: '个人中心'}子路由必须定义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'

  • 先const path = childRoute.component.split('/')拆分一下路径,这时候path = ['user', 'info']
  • 因为import()根据变量导入只能深入一层文件,如果直接导入user/info,这样会报错,需要先拆分然后再拼起来
  • 然后根据path动态导入路由,并赋值给子路由的component字段。需要保证/views目录下有这样的组件
// 路径必须以绝对路径,相对路径或@开头,文件名结尾,vite官网有说明  
// 不符合的话导入报错  
childRoute.component = () => import(`@/views/${path[0]}/${path[1]}.vue`)  

如果component: 'welcome'

  • 这时候组件的路径就等于path = ['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>  
        &lt;div style="display: flex; gap: 50px; align-items: flex-end;"&gt;  
        &lt;template v-for="menu in server_route"&gt;  
            &lt;!-- 显示多级菜单--&gt;  
            &lt;div v-if="!menu.meta.single"&gt;  
                &lt;h5&gt;{{ menu.meta.menuName }}&lt;/h5&gt;  
                &lt;button  
                    v-for="child in menu.children"  
                    @click="router.push({name: child.name})"&gt;  
                    {{ child.meta.menuName }}  
                &lt;/button&gt;  
            &lt;/div&gt;  

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

    &lt;hr&gt;  
    &lt;button v-show="needAddRoutes" @click="login"&gt;模拟登录获取路由&lt;/button&gt;  

    &lt;main&gt;  
        &lt;router-view /&gt;  
    &lt;/main&gt;  
&lt;/div&gt;  

</template>

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

总结

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

到此这篇关于vue3动态路由+菜单栏的实现示例的文章就介绍到这了,更多相关vue3动态路由+菜单栏内容请搜索网赚博客https://www.piaodoo.com/以前的文章或继续浏览下面的相关文章希望大家以后多多支持网赚博客https://www.piaodoo.com/!

                        友情连接:  

茂名一技http://www.szsyby.net/


茂名一技http://www.enechn.com/


美文集http://www.tpyjn.cn/


手游排行前十名http://www.bjkhrx.com/


蔚来汽车http://www.weilaiqiche.cn/

### ElementUI 实现动态路由菜单 为了实现Vue 中使用 Element UI 组件库创建动态路由菜单,通常会涉及几个核心部分:用户权限验证、从服务器获取菜单数据以及根据这些数据生成对应的路由配置。 #### 获取并解析菜单数据 当用户成功登录后,应用程序应当向服务器发送请求以获得该用户的访问权限列表。此操作可以通过 Axios 或者 Fetch API 完成。一旦接收到响应中的 JSON 数据,则可以根据预定义的逻辑来处理它: ```javascript // 假设这是来自服务器的原始菜单数据 const menuData = [ { path: &#39;/home&#39;, name: &#39;Home&#39;, component: () => import(&#39;@/views/Home.vue&#39;), meta: { title: &#39;首页&#39;, icon: &#39;el-icon-s-home&#39; } }, // 更多路径... ]; ``` 上述代码片段展示了如何定义一个简单的菜单项数组 `menuData`[^2]。 #### 创建动态路由函数 接下来需要编写一段 JavaScript 函数用于遍历 `menuData` 并将其转换为适合 Vue Router 的格式。这一步骤可能涉及到递归地构建子级路由对象,并确保每个节点都包含了必要的属性如 `path`, `component`, 和 `children`. ```javascript function generateRoutes(menuItems) { return menuItems.map(item => ({ ...item, children: item.children ? generateRoutes(item.children) : undefined })); } ``` 这段代码实现了将传入的菜单项目转化为适用于 Vue Router 配置的对象结构的功能[^1]。 #### 将新路由添加路由器实例 最后,在应用初始化阶段调用上面提到的方法并将返回的结果传递给 Vue Router 的 `.addRoutes()` 方法(对于 Vue Router v3.x 版本),从而完成整个流程: ```javascript import router from &#39;./router&#39;; // 导入已有的静态路由表 axios.get(&#39;/api/user/menus&#39;) .then(response => { const dynamicRoutes = generateRoutes(response.data); router.addRoutes(dynamicRoutes); // 对于 Vue Router 3.x 使用 addRoutes() next({ ...to }); // 如果有未匹配成功的跳转需求, 可在此处重定向 }); ``` 注意:如果是使用 Vue Router 4.x+, 则不再支持直接调用 `addRoutes()`. 此时应该考虑采用编程方式导航或者利用其他机制实现相似效果. #### 渲染左侧菜单栏 有了完整的路由信息之后就可以轻松地借助 Element UI 提供的各种组件比如 `<el-menu>` 来展示最终的效果了。下面是一个简化版的例子说明怎样把之前准备好的路由映射到可视化的菜单上: ```html <template> <div id="app"> <!-- 左侧菜单 --> <el-aside width="200px"> <el-menu default-active="/home" unique-opened router> <sidebar-item v-for="(route,i) of routes" :key="i" :item="route"/> </el-menu> </el-aside> <!-- 主要内容区域 --> <main class="content"> <router-view></router-view> </main> </div> </template> <script> export default { computed:{ routes(){ return this.$router.options.routes.filter(route=>!route.hidden) } } }; </script> ``` 在这个模板中,`routes` 计算属性过滤掉了任何带有隐藏标志 (`hidden`) 的路由条目;而自定义组件 `SidebarItem` 负责迭代每一个顶层路由及其潜在的孩子们,进而形成层次分明的菜单体系[^3]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值