Files
workspace/code/g3soft-libs/docs/content/ui/overlay/dropdown.md
T
2026-10-09 17:32:14 +08:00

6.0 KiB
Raw Blame History

title, description
title description
Dropdown 下拉菜单 点击 / 悬停 / 右键触发的操作列表,支持子菜单与键盘导航

Dropdown 下拉菜单

Dropdown 把一组操作收进一个菜单,用于行内操作(编辑/复制/删除)、账号菜单与右键菜单。

何时使用

  • 操作多于 2 个、或含危险操作需要分组时,收进菜单比并排按钮更清晰;
  • 表格行、树节点、卡片上承载右侧的「更多操作」;
  • 右键上下文菜单(trigger="contextmenu");
  • 只有一个操作时不要用菜单,直接放按钮。

数据源写法

items 是最常用的写法,点击后通过 click 事件回传 { key, item }。

声明式写法

也可以把 G3DropdownItem 写在插槽里:它不渲染任何 DOM,只作为数据载体被 Dropdown 收集,因此键盘导航、高亮、子菜单这些能力与 items 写法完全一致。使用声明式写法时建议用 #trigger 显式指定触发器,避免触发器跟菜单项混在默认插槽里。

触发方式

菜单项类型

项配置 说明
{ key, label } 普通项,点击回传 key
{ icon } 前置图标(组件或 VNode)
{ shortcut } 右侧快捷键提示文字(仅展示,不绑定按键)
{ disabled } 禁用项:不可点、键盘导航跳过
{ danger } 危险项:红色文字
{ divider: true } 分隔线
{ type: 'label', label } 分组标签
{ children: [...] } 子菜单,hover 展开(right-start 弹出)
{ onClick: (item) => void } 项自带回调,先于全局 click 事件执行

富头部与自定义菜单

#header 用于账号卡片之类的头部(不参与键盘导航);#menu 是完全自定义菜单结构的逃生舱。

键盘操作

菜单打开后焦点会进入菜单容器,因此可以直接用键盘:

按键 行为
↑ / ↓ 移动高亮(跳过分隔线、分组标签与禁用项,循环)
Home / End 跳到首 / 末项
Enter 选中高亮项并关闭菜单(有子菜单的父项只高亮,不选中)
Esc 关闭菜单(由 Popover 处理)

API

Props

名称 类型 默认值 说明
items DropdownItemData[] — 菜单项数组;不传时从默认插槽收集 G3DropdownItem,否则回退到 #menu
open boolean — 受控打开状态;不传即非受控
defaultOpen boolean false 非受控时的初始状态
trigger 'click' | 'hover' | 'contextmenu' 'click' 触发方式
placement Placement 'bottom-start' 菜单方位
disabled boolean false 禁用
mouseEnterDelay number 100 hover 打开延迟(ms)
mouseLeaveDelay number 200 hover 关闭延迟(ms)。有子菜单时适当调大
offset number 4 与触发器的间距(px)
unwrapped boolean true 零包裹模式,触发器不额外包 <span>

Events

名称 参数 说明
click ({ key, item }) 选中某个菜单项(不含分隔线 / 分组标签)
update:open (open: boolean) 打开状态变化
openChange (open: boolean) 同上,语义别名

Slots

名称 参数 说明
default — 触发器(未传 #trigger 时);或一组 G3DropdownItem
trigger — 显式指定触发器(推荐)
header — 菜单顶部富内容(不参与键盘导航)
menu { close: () => void } 完全自定义菜单结构(无 items 与 G3DropdownItem 时生效)

Props(G3DropdownItem)

名称 类型 默认值 说明
itemKey string | number — 标识,点击时回传
label string '' 菜单文本
icon Component — 前置图标
danger boolean false 危险项
disabled boolean false 禁用项
divider boolean false 渲染为分隔线(其余属性忽略)
onClick (item) => void — 项自带回调

类型定义

export interface DropdownItemData {
  key?: string | number
  label?: string
  icon?: Component | VNode
  danger?: boolean
  disabled?: boolean
  shortcut?: string
  divider?: boolean
  type?: 'label'
  children?: DropdownItemData[]
  onClick?: (item: DropdownItemData) => void
}

export interface DropdownClickPayload {
  key?: string | number
  item: DropdownItemData
}

样式变量

变量 默认值 说明
--g3-dropdown-min-width 180px 菜单最小宽度
--g3-dropdown-max-height 256px 菜单最大高度(超出滚动)
--g3-dropdown-item-padding-y / -x 5px / 8px 菜单项内边距
--g3-dropdown-item-radius 4px 菜单项圆角
--g3-dropdown-divider-margin 4px 0 分隔线外边距

实现说明

  • 三种数据源统一成一份 items 数组:声明式的 G3DropdownItem 由 Dropdown 在渲染时收集(读取 vnode.props),随后与 items 走完全相同的渲染与键盘逻辑,因此不会出现「声明式写法少了某个能力」的问题;
  • 菜单容器是可聚焦的(tabindex="-1"),打开后主动 focus(),键盘事件因此能被菜单自身接收,不需要全局监听;
  • 子菜单是嵌套的 Popover(trigger="hover"、placement="right-start"),递归渲染 items;子菜单内部 interactive=false,不参与主菜单的高亮联动;
  • 打开时把 z-index 打到 popup 档,关闭回收;右键触发时浮层对齐鼠标位置;
  • 菜单项高亮用 activeIndex 单值驱动,鼠标移入与键盘移动共用它,因此「键盘移动后鼠标移入」不会出现双高亮。