菜单
Menu 用于显示一组操作命令或选项。支持点击、悬停、右键等多种触发方式,并提供了灵活的定位策略。
组件调用
使用 <TuiMenu> 组件包裹触发元素(如按钮)。默认情况下,它是一个右键菜单 (trigger="contextmenu"),但在常规交互中,我们常将其设为 click 或 hover。
vue
<script setup>
import { reactive } from 'vue'
const menuItems = [
{ label: '复制', value: 'copy', icon: 'tui-icon ti-copy' },
{ label: '粘贴', value: 'paste', icon: 'tui-icon ti-paste' },
{ label: '删除', value: 'delete', icon: 'tui-icon ti-trash', divider: true },
{ label: '属性', value: 'prop', icon: 'tui-icon ti-info-circle' }
]
const handleMenuClick = (params) => {
console.log('点击了:', params)
}
</script>
<template>
<TuiMenu
trigger="click"
placement="bottom-start"
:menus="menuItems"
@menuClick="handleMenuClick"
>
<TuiButton>点击打开菜单</TuiButton>
</TuiMenu>
</template>指令调用
TechUI 提供了 v-tui-menu 指令,这是更轻量、更推荐的用法,可以直接挂载到任何 DOM 元素上,无需改变 DOM 结构。
vue
<template>
<TuiButton
v-tui-menu="{
trigger: 'hover',
placement: 'top',
menus: menuItems,
menuClick: handleMenuClick
}"
>
悬停查看菜单
</TuiButton>
</template>触发方式
通过 trigger 属性控制菜单的激活方式:
- click: 左键点击触发(下拉菜单)。
- hover: 鼠标悬停触发(二级菜单或提示)。
- contextmenu: 右键点击触发(上下文菜单)。
vue
<template>
<div class="demo-box">
<TuiButton v-tui-menu="{ trigger: 'click', menus: [...] }">
点击触发
</TuiButton>
<TuiButton v-tui-menu="{ trigger: 'hover', menus: [...] }">
悬停触发
</TuiButton>
<div
class="context-area"
v-tui-menu="{ trigger: 'contextmenu', menus: [...] }"
>
在此区域点击右键
</div>
</div>
</template>菜单项配置
菜单项数据 (menus) 支持丰富的配置,包括图标、快捷键描述、分割线以及角标(Tag/Badge)。
vue
<script setup>
const richMenus = [
{
label: '新建文件',
value: 'new',
icon: 'tui-icon ti-file',
description: 'Ctrl+N' // 右侧快捷键提示
},
{
label: '保存',
value: 'save',
icon: 'tui-icon ti-save',
divider: true // 显示分割线
},
{
label: '消息通知',
value: 'msg',
icon: 'tui-icon ti-bell',
tagContent: 8, // 显示数字角标
tagType: 'success' // 角标颜色类型
},
{
label: '紧急任务',
value: 'urgent',
tagContent: 'Urgent', // 显示文字角标
tagType: 'danger'
}
]
</script>
<template>
<TuiMenu trigger="click" :menus="richMenus">
<TuiButton>打开丰富菜单</TuiButton>
</TuiMenu>
</template>方位与定位
支持 12 个方位的精准定位,能够适应复杂的页面布局。
top, top-start, top-end, bottom, bottom-start, bottom-end, left, left-start, left-end, right, right-start, right-end。
vue
<template>
<div class="row">
<TuiButton v-tui-menu="{ placement: 'top-start', menus: [...] }">Top Start</TuiButton>
<TuiButton v-tui-menu="{ placement: 'top', menus: [...] }">Top</TuiButton>
<TuiButton v-tui-menu="{ placement: 'top-end', menus: [...] }">Top End</TuiButton>
</div>
<div class="row">
<TuiButton v-tui-menu="{ placement: 'right', menus: [...] }">Right</TuiButton>
</div>
</template>API 参考
Menu Props (组件属性)
| 属性名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| menus | 菜单项数据列表 (见下表) | Array | [] |
| trigger | 触发方式,可选 'click', 'hover', 'contextmenu' | String | 'contextmenu' |
| placement | 弹出位置,可选 top/bottom/left/right 及其 start/end 组合 | String | 'bottom-start' |
| offset | 弹出的偏移量 (px) | Number | 8 |
| maxWidth | 菜单最大宽度 (px) | Number | 200 |
| zIndex | 菜单层级 | Number | 2000 |
| disabled | 是否禁用 | Boolean | false |
| menuClick | 菜单项点击的回调函数 | Function | null |
| appendTo | 指定挂载的 DOM 节点选择器 (仅组件模式) | String | — |
| className | 自定义类名 | String | '' |
Menu Item Options (菜单项配置)
menus 数组中的对象结构:
| 属性名 | 说明 | 类型 |
|---|---|---|
| label | 菜单项显示的文本 | String |
| value | 菜单项的唯一标识值 (点击回调中返回) | String / Number |
| icon | 图标类名 (如 tui-icon ti-copy) | String |
| description | 右侧辅助文本 (常用于快捷键提示) | String |
| divider | 是否在该项下方显示分割线 | Boolean |
| tagContent | 角标内容 (数字或文本) | String / Number |
| tagType | 角标类型 (颜色),可选 primary, success, warning, danger | String |
Events
| 事件名 | 说明 | 回调参数 |
|---|---|---|
| menuClick | 点击菜单项时触发 | (params: Object, item: Object, index: Number) |
Expose
| 名称 | 说明 | 类型 |
|---|---|---|
| show | 手动显示菜单 | () => void |
| hide | 手动隐藏菜单 | () => void |
| toggle | 切换显示状态 | () => void |
全局交互监控
为了提供精准的闭合体验,TuiMenu 组件深度集成了 TechUI 的全局服务(TuiService),通过监听两个核心计数器来实现智能交互:
- ESC 响应 (
escCounter):组件实时监测全局 ESC 键的触发。当用户按下 Esc 键时,escCounter发生变化,所有激活状态的菜单将自动关闭。 - 智能点击检测 (
clickCounter):组件监听全局点击事件。每次点击发生时,全局服务会更新clickCounter并传递当前的clickTarget(点击目标元素)。组件会利用这一参数进行包含检测(Contains Check):只有当点击目标既不在菜单面板内部,也不在触发元素内部时,才会触发隐藏逻辑。这种机制确保了在复杂的嵌套 DOM 结构中,点击外部关闭(Click Outside)的逻辑依然精准无误。
定位依赖
TechUI 的气泡与弹层组件底层完全依赖于业界成熟的 Floating UI 库进行锚点定位计算。
这意味着您无需担心复杂的几何计算,组件能够自动处理以下场景:
- 碰撞检测 (Flip):当预设位置空间不足时(如屏幕边缘),自动翻转到对面位置。
- 视口修正 (Shift):确保气泡始终保持在视口可见范围内,不会被截断。
- 精准偏移:通过
offset属性实现像素级的精确定位。
您只需通过组件的 placement 属性指定期望方位,剩下的复杂计算均由底层引擎自动完成。