7.3 el-menu
<el-menu>
。它是构建网站或应用侧边栏导航、顶部导航栏等结构化导航系统的强大工具
核心概念与组成
一个 el-menu
由以下几个关键部分构成:
<el-menu>
: 菜单的根容器,负责管理整体布局、模式、激活状态等。<el-menu-item>
: 顶级菜单项或叶子菜单项。代表一个可点击的导航链接,通常对应一个具体的路由或功能。<el-sub-menu>
: 子菜单容器。用于包裹一个菜单标题和其下的子菜单项 (el-menu-item
或嵌套的el-sub-menu
),实现多级菜单结构。<el-menu-item-group>
: 菜单项分组。用于将一组相关的el-menu-item
分组显示,通常带有分组标题。<el-menu-divider>
: 菜单分隔线。用于在菜单项之间添加视觉分隔。
<el-menu>
详解 (核心容器)
- 作用: 菜单的整体容器,定义菜单的基本行为和外观。
- 核心属性:
mode
: 核心属性。定义菜单的展示模式。horizontal
: 水平模式。菜单项水平排列,常用于顶部导航栏。vertical
: 垂直模式。菜单项垂直排列,常用于侧边栏。这是默认值。
default-active
: 当前激活菜单的index
。通常绑定到当前路由的路径($route.path
),用于高亮显示当前页面对应的菜单项。default-openeds
: 默认展开的子菜单的index
数组。在垂直模式下,可以指定哪些el-sub-menu
初始时是展开的。unique-opened
: 是否只保持一个子菜单的展开。设置为true
时,展开一个子菜单后,会自动收起其他已展开的子菜单。在侧边栏中很常用。menu-trigger
: 子菜单的触发方式。仅在mode="horizontal"
时有效。hover
: 鼠标悬停时触发(默认)。click
: 点击时触发。
collapse
: 核心属性 (侧边栏)。是否水平折叠收起菜单(仅在mode="vertical"
时可用)。设置为true
时,菜单收起为窄栏,通常只显示图标。常与collapse-transition
配合使用。collapse-transition
: 是否开启折叠动画。默认true
。router
: 是否启用 Vue Router 模式。设置为true
后,el-menu-item
的index
属性会被当作路由路径,点击时会触发router.push(index)
进行导航。这是实现菜单与路由深度集成的关键。background-color
: 菜单的背景色。text-color
: 菜单的文字颜色。active-text-color
: 当前激活菜单的文字颜色。ellipsis
: 当菜单项文本过长时,是否显示省略号 (...
)。默认true
。indent
: 子菜单的缩进距离(单位 px)。默认20
。
- 核心事件:
open
: 当展开某个子菜单时触发。回调参数(index: string, indexPath: string[])
。close
: 当收起某个子菜单时触发。回调参数同上。select
: 当菜单项被点击选中时触发。回调参数(index: string, indexPath: string[], item: ElMenuItem, routerResult?: any)
。routerResult
是router.push
返回的 Promise 结果(如果启用了router
模式)。这是处理非路由菜单项点击的主要事件。
- 插槽 (Slots):
- 默认插槽: 放置
el-menu-item
,el-sub-menu
,el-menu-item-group
,el-menu-divider
。
- 默认插槽: 放置
<el-menu-item>
详解 (菜单项)
- 作用: 表示一个具体的、可点击的菜单选项。
- 核心属性:
index
: 必需。唯一标识符。在router
模式下,它作为路由路径;在非router
模式下,它是select
事件的参数。必须保证在同一级菜单中唯一。route
: Vue Router 的路由对象。如果设置了此属性,点击该项会导航到该路由,优先级高于index
。常用于需要传递参数的路由。disabled
: 是否禁用该项。
- 插槽:
- 默认插槽: 放置菜单项的文本内容。
title
: 自定义菜单项的标题(文本部分),可以包含 HTML 或组件。
<el-sub-menu>
详解 (子菜单)
- 作用: 容器,用于创建可展开/收起的子菜单。
- 核心属性:
index
: 必需。子菜单的唯一标识符。popper-class
: 自定义弹出菜单的class
。teleported
: 是否将子菜单的 DOM 元素使用Teleport
移动到body
下。默认true
,有助于解决z-index
和overflow
问题。show-timeout
/hide-timeout
: 子菜单展开/隐藏的延迟时间(毫秒)。
- 插槽:
- 默认插槽: 放置子菜单下的
el-menu-item
和el-sub-menu
。 title
: 必需。定义子菜单的标题内容(显示在主菜单上的部分),通常包含图标和文本。
- 默认插槽: 放置子菜单下的
<el-menu-item-group>
与 <el-menu-divider>
<el-menu-item-group>
: 用于对el-menu-item
进行逻辑分组。它有一个title
属性来设置分组标题。<el-menu-divider>
: 简单的分隔线组件,没有属性,直接插入即可。
工作原理与关键点
index
是灵魂:el-menu
通过index
属性来识别和管理每一个菜单项和子菜单。default-active
通过匹配index
来确定哪个项是激活状态。router
模式: 当el-menu
设置了router="true"
,el-menu-item
的index
会被当作路由路径使用router.push
进行导航。default-active
通常绑定到$route.path
以实现自动高亮。collapse
模式: 在侧边栏应用中,通过一个布尔值控制collapse
属性,可以实现菜单的展开/收起动画。收起时,通常只显示图标,需要为el-menu-item
和el-sub-menu
的title
插槽设计好图标。- 事件流:
select
事件由el-menu-item
触发,被el-menu
捕获。open
/close
事件由el-sub-menu
触发,被el-menu
捕获。 teleported
: 对于复杂的布局(如菜单在overflow: hidden
的容器内),teleported="true"
可以确保子菜单正确弹出,不受父级样式限制。
常用示例
示例 1: 基础垂直侧边栏菜单
<template><el-menu:default-active="$route.path"class="el-menu-vertical-demo"@open="handleOpen"@close="handleClose"@select="handleSelect"router <!-- 启用路由模式 -->><el-menu-item index="/home"><el-icon><HomeFilled /></el-icon><span>首页</span></el-menu-item><el-menu-item index="/user"><el-icon><User /></el-icon><span>用户管理</span></el-menu-item><el-sub-menu index="article"><template #title><el-icon><Document /></el-icon><span>文章管理</span></template><el-menu-item index="/article/list">文章列表</el-menu-item><el-menu-item index="/article/create">创建文章</el-menu-item></el-sub-menu><el-menu-item-group title="工具"><el-menu-item index="/tools/calculator">计算器</el-menu-item><el-menu-item index="/tools/converter">转换器</el-menu-item></el-menu-item-group><el-menu-divider /><el-menu-item index="/settings"><el-icon><Setting /></el-icon><span>设置</span></el-menu-item></el-menu>
</template><script setup>
import { HomeFilled, User, Document, Setting } from '@element-plus/icons-vue'
import { useRouter } from 'vue-router'const router = useRouter()const handleOpen = (index, indexPath) => {console.log('open:', index, indexPath)
}
const handleClose = (index, indexPath) => {console.log('close:', index, indexPath)
}
const handleSelect = (index, indexPath) => {console.log('select:', index, indexPath)// 如果没有启用 router 模式,这里可以手动导航// router.push(index)
}
</script><style scoped>
/* 可以在这里自定义样式 */
</style>
示例 2: 可折叠的侧边栏
<template><div class="sidebar-container"><!-- 折叠按钮 --><el-button @click="toggleCollapse" style="margin: 10px;">{{ isCollapse ? '展开' : '收起' }}</el-button><!-- 菜单 --><el-menu:default-active="$route.path"class="el-menu-vertical-demo":collapse="isCollapse":collapse-transition="true"routerunique-opened><el-menu-item index="/dashboard"><el-icon><HomeFilled /></el-icon><template #title>仪表盘</template> <!-- #title 等同于 v-slot:title --></el-menu-item><el-sub-menu index="system"><template #title><el-icon><Setting /></el-icon><span>系统管理</span></template><el-menu-item index="/system/user">用户管理</el-menu-item><el-menu-item index="/system/role">角色管理</el-menu-item></el-sub-menu></el-menu></div>
</template><script setup>
import { ref } from 'vue'
import { HomeFilled, Setting } from '@element-plus/icons-vue'const isCollapse = ref(false) // 控制折叠状态const toggleCollapse = () => {isCollapse.value = !isCollapse.value
}
</script><style scoped>
.sidebar-container {width: 200px; /* 或根据 isCollapse 动态调整 */border-right: 1px solid #e6e6e6;
}
/* 当菜单收起时,隐藏文字 */
.el-menu--collapse span {height: 0;width: 0;overflow: hidden;visibility: hidden;display: inline-block;
}
/* 也可以通过 CSS 类控制图标居中 */
.el-menu--collapse .el-menu-item .el-icon,
.el-menu--collapse .el-sub-menu__title .el-icon {margin-right: 0;display: block;margin: 0 auto;
}
</style>
示例 3: 水平顶部导航
<template><el-menu:default-active="$route.path"mode="horizontal":ellipsis="false" <!-- 顶部导航通常不省略 -->router><el-menu-item index="/">首页</el-menu-item><el-menu-item index="/products">产品中心</el-menu-item><el-sub-menu index="services"><template #title>服务支持</template><el-menu-item index="/services/faq">常见问题</el-menu-item><el-menu-item index="/services/contact">联系我们</el-menu-item></el-sub-menu><el-menu-item index="/about">关于我们</el-menu-item></el-menu>
</template>
示例 4: 使用 route
属性 (传递参数)
<template><el-menu :default-active="$route.path" router><el-menu-item :route="{ name: 'UserProfile', params: { id: 123 } }" index="profile">我的资料</el-menu-item></el-menu>
</template>
- 解析: 点击 "我的资料",会导航到名为
UserProfile
的路由,并传递参数{ id: 123 }
。index="profile"
在这里主要用于default-active
的匹配。
使用建议与最佳实践
router
模式优先: 如果你的应用使用 Vue Router,强烈建议启用router="true"
并利用index
作为路径,这能极大简化导航逻辑和激活状态管理。default-active
绑定路由: 将default-active
绑定到$route.path
或$route.fullPath
,实现页面切换时菜单的自动高亮。unique-opened
: 在侧边栏中,通常设置unique-opened="true"
以提供更清晰的导航体验。collapse
的 CSS: 当菜单收起时,需要通过 CSS 隐藏文本 (visibility: hidden
) 并可能调整图标位置,确保窄栏美观。teleported
: 除非有特殊需求,保持teleported="true"
以避免布局问题。- 性能: 对于非常庞大的菜单,考虑虚拟滚动或分组加载。
- 无障碍性 (a11y): 确保菜单结构清晰,使用语义化标签。
- 主题定制: 通过
background-color
,text-color
,active-text-color
或 SCSS 变量深度定制菜单外观。 menu-trigger
: 在移动端或需要精确控制的场景,可以将水平菜单的触发方式改为click
。- 事件处理:
select
事件是处理非路由导航或额外逻辑的主要入口。
el-menu
是构建现代 Web 应用导航结构的基石。掌握其模式、路由集成和折叠功能,可以高效地创建出专业、用户体验良好的导航系统。