vue3 左侧菜单动态路由
时间: 2025-01-04 07:27:02 浏览: 7
### Vue3 实现左侧菜单动态路由配置
#### 路由与菜单结构设计
为了实现基于用户权限的动态路由和菜单,在项目初始化阶段应构建基础框架。考虑到不同角色拥有不同的访问权限,需预先规划好哪些页面属于公共部分,哪些则受权限限制[^2]。
#### 创建动态路由表
通过向后台请求获取当前登录用户的可访问资源列表,并据此生成对应的前端路由对象数组。每个路由项通常包含`path`, `component`, 和用于描述性的元数据(`meta`)字段,其中`meta`可用于存储诸如菜单名、图标样式等辅助信息[^3]。
```javascript
// src/api/menu.js 示例API调用函数
export function getMenuList() {
return axios.get('/api/menus');
}
```
```typescript
// store/modules/app.ts Vuex模块处理逻辑片段
import { defineStore } from "pinia";
import type { RouteRecordRaw } from 'vue-router';
import { useRouter } from 'vue-router';
const useAppStore = defineStore('app', {
state: () => ({
dynamicRoutes: [] as Array<RouteRecordRaw>,
}),
actions: {
async setDynamicRoutes() {
try {
const response = await getMenuList();
this.dynamicRoutes = buildRouteFromMenu(response.data);
// 添加到全局路由器实例中
const router = useRouter();
this.dynamicRoutes.forEach(route => {
router.addRoute(route);
});
} catch (error) {
console.error(error);
}
},
// 构建路由的方法...
}
});
```
#### 渲染侧边栏组件
对于菜单UI层面上的表现形式,则依赖于具体的设计稿来决定采用何种方式呈现给终端使用者。一般情况下,可以通过遍历上述提到过的带有`meta`属性的对象集合来进行DOM节点拼接工作;同时配合CSS框架完成美化效果[^1]。
```html
<!-- components/Sidebar.vue -->
<template>
<el-menu :default-active="activePath">
<sidebar-item v-for="(item, index) in menuData" :key="index" :data="item"/>
</el-menu>
</template>
<script setup lang="ts">
import SidebarItem from './SidebarItem.vue'
import { computed } from 'vue';
import { useRoute } from 'vue-router';
import { useAppStore } from '@/store/modules/app'
const route = useRoute()
const appStore = useAppStore()
const activePath = computed(() => route.path)
defineProps<{
menuData?: any[]
}>()
</script>
```
```html
<!-- components/SidebarItem.vue 单个菜单项模板 -->
<template>
<div v-if="!isHidden(item)">
<!-- 多级菜单展开收缩按钮 -->
<el-submenu v-if="hasChildren(item)" :index="String(index)">
<template slot="title">{{ item.meta.menuName }}</template>
<sidebar-item v-for="(child, i) in item.children" :key="i" :data="child"></sidebar-item>
</el-submenu>
<!-- 直达链接 -->
<router-link v-else class="submenu-title-noDropdown" to={item.path}>
{{ item.meta.menuName }}
</router-link>
</div>
</template>
<script setup lang="ts">
interface MenuItemType {
meta: Record<string, unknown>;
children?: MenuItemType[];
}
function isHidden(menuItem: MenuItemType): boolean {
return menuItem?.meta?.hidden === true;
}
function hasChildren(menuItem: MenuItemType): boolean {
return Array.isArray(menuItem.children) && menuItem.children.length > 0;
}
defineProps<{
data: MenuItemType,
index: number
}>()
</script>
```
阅读全文