vue3动态路由+菜单栏的实现示例 |
动态路由这里用vue3和vite来实现动态路由,点击这里查看效果 源码 使用场景在后台管理系统,可以根据登录用户的不同返回不同路由,页面也会根据这些路由生成对应的菜单 。这样通过服务器就能控制一个用户可以访问的内容了 。 步骤定义基础路由表 代码服务器路由数据这里模拟服务器返回的数据,为了方便只写了一条路由,看源码有更多示例 。 [ { 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字段转成真实的路由 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动态路由+菜单栏内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持! |