vue实现menu
Vue 实现 Menu 组件
基础 Menu 实现
使用 Vue 3 的 Composition API 可以快速实现一个基础的 Menu 组件。以下是一个简单的实现示例:
<template>
<div class="menu">
<div
v-for="item in items"
:key="item.id"
class="menu-item"
@click="selectItem(item)"
>
{{ item.label }}
</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
const props = defineProps({
items: {
type: Array,
required: true,
default: () => []
}
});
const emit = defineEmits(['select']);
const selectItem = (item) => {
emit('select', item);
};
</script>
<style scoped>
.menu {
display: flex;
flex-direction: column;
gap: 8px;
padding: 8px;
background: white;
border-radius: 4px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.menu-item {
padding: 8px 12px;
cursor: pointer;
border-radius: 4px;
}
.menu-item:hover {
background: #f5f5f5;
}
</style>
嵌套子菜单
实现带子菜单的 Menu 组件需要递归组件技术:
<template>
<div class="menu-item" @mouseenter="showSubmenu = true" @mouseleave="showSubmenu = false">
<div class="menu-item-content">
{{ item.label }}
<span v-if="item.children">▶</span>
</div>
<div v-if="item.children && showSubmenu" class="submenu">
<Menu :items="item.children" @select="handleSelect"/>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
import Menu from './Menu.vue';
const props = defineProps({
item: Object
});
const emit = defineEmits(['select']);
const showSubmenu = ref(false);
const handleSelect = (item) => {
emit('select', item);
};
</script>
<style scoped>
.menu-item {
position: relative;
padding: 8px 12px;
cursor: pointer;
}
.menu-item-content {
display: flex;
justify-content: space-between;
align-items: center;
}
.submenu {
position: absolute;
left: 100%;
top: 0;
min-width: 150px;
background: white;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
border-radius: 4px;
}
</style>
使用 Vue Router 集成
当 Menu 需要与路由配合时,可以使用 Vue Router 的 <router-link>:

<template>
<div class="menu">
<router-link
v-for="item in items"
:key="item.path"
:to="item.path"
class="menu-item"
active-class="active"
>
{{ item.meta?.title || item.name }}
</router-link>
</div>
</template>
<script setup>
defineProps({
items: {
type: Array,
required: true
}
});
</script>
<style scoped>
.menu-item {
display: block;
padding: 8px 12px;
text-decoration: none;
color: inherit;
}
.active {
background: #e0f2fe;
color: #0369a1;
}
</style>
响应式设计
针对移动设备优化 Menu 显示:
<template>
<button @click="toggleMenu">菜单</button>
<div v-if="isOpen" class="mobile-menu">
<div
v-for="item in items"
:key="item.id"
class="menu-item"
@click="selectItem(item)"
>
{{ item.label }}
</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
const isOpen = ref(false);
const props = defineProps({
items: Array
});
const toggleMenu = () => {
isOpen.value = !isOpen.value;
};
const selectItem = (item) => {
isOpen.value = false;
emit('select', item);
};
</script>
<style scoped>
.mobile-menu {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100vh;
background: white;
z-index: 100;
padding: 20px;
}
@media (min-width: 768px) {
.mobile-menu {
position: static;
width: auto;
height: auto;
padding: 0;
}
}
</style>
使用 UI 库
如果需要更完整的解决方案,可以考虑使用现成的 UI 库:

-
Element Plus Menu 组件:
<template> <el-menu :default-active="activeIndex" class="el-menu-demo" mode="horizontal" @select="handleSelect" > <el-menu-item index="1">首页</el-menu-item> <el-sub-menu index="2"> <template #title>产品</template> <el-menu-item index="2-1">产品1</el-menu-item> <el-menu-item index="2-2">产品2</el-menu-item> </el-sub-menu> </el-menu> </template> -
Ant Design Vue Menu 组件:
<template> <a-menu v-model:selectedKeys="current" mode="horizontal"> <a-menu-item key="mail">导航1</a-menu-item> <a-menu-item key="app">导航2</a-menu-item> <a-sub-menu key="sub"> <template #title>导航3</template> <a-menu-item key="sub1">选项1</a-menu-item> <a-menu-item key="sub2">选项2</a-menu-item> </a-sub-menu> </a-menu> </template>






