---
title: "DropdownMenu 下拉菜单"
description: "从触发器展开的短命令菜单"
category: Navigation
status: beta
since: 0.3.4
tags: [dropdown, menu, popover]
syncStatus: reviewed
verified: true
---

## 用法

### 基础
选中后先闪烁确认再关闭；设置 `activation-feedback="false"` 的条目立即执行。
:::TuffDemoWrapper{demo="DropdownMenuDropdownMenuDemo" code-lang="vue"}
---
code: |
  <template>
    <TxDropdownMenu>
      <template #trigger>
        <TxButton>菜单</TxButton>
      </template>

      <TxDropdownItem>打开（闪烁确认）</TxDropdownItem>
      <TxDropdownItem :activation-feedback="false">立即执行（关闭反馈）</TxDropdownItem>
      <TxDropdownItem danger>删除</TxDropdownItem>
    </TxDropdownMenu>
  </template>
---
:::

### 子菜单
`TxDropdownSubmenu` 嵌套任意层级的子面板，悬停触发行即展开。
:::TuffDemoWrapper{demo="DropdownMenuDropdownSubmenuDemo" code-lang="vue"}
---
code: |
  <template>
    <TxDropdownMenu>
      <template #trigger>
        <TxButton>操作</TxButton>
      </template>

      <TxDropdownItem>打开</TxDropdownItem>
      <TxDropdownSubmenu>
        导出为…
        <template #menu>
          <TxDropdownItem>PNG</TxDropdownItem>
          <TxDropdownItem>SVG</TxDropdownItem>
          <TxDropdownSubmenu>
            更多格式
            <template #menu>
              <TxDropdownItem>WebP</TxDropdownItem>
              <TxDropdownItem>AVIF</TxDropdownItem>
            </template>
          </TxDropdownSubmenu>
        </template>
      </TxDropdownSubmenu>
    </TxDropdownMenu>
  </template>
---
:::

### 导航样式
`trigger` 插槽接受任意元素；`right` 插槽替换条目右侧的箭头。
:::TuffDemoWrapper{demo="DropdownMenuDropdownMenuNavDemo" code-lang="vue"}
---
code: |
  <template>
    <TxDropdownMenu v-model="open" :min-width="240">
      <template #trigger>
        <div class="nav-trigger">
          设计 <span>生态</span>
          <TxIcon name="chevron-down" />
        </div>
      </template>

      <TxDropdownItem>
        GitHub
        <template #right>
          <i class="i-carbon-launch" />
        </template>
      </TxDropdownItem>
      <TxDropdownItem>
        NPM
        <template #right>
          <i class="i-carbon-launch" />
        </template>
      </TxDropdownItem>
    </TxDropdownMenu>
  </template>
---
:::

### 后台导航
`TxTabs` 固定一级分区，轻操作放进 `TxDropdownMenu`，短说明放进 `TxPopover`，高密度配置放进 `TxDrawer`。
:::TuffDemoWrapper{demo="ComponentsNavigationShellDemo" code-lang="vue"}
---
code: |
  <template>
    <TxDropdownMenu>
      <template #trigger>
        <TxButton>发布操作</TxButton>
      </template>
      <TxDropdownItem>快速发布</TxDropdownItem>
    </TxDropdownMenu>

    <TxPopover>
      <template #reference>
        <TxButton variant="secondary">策略说明</TxButton>
      </template>
      浮层只放短说明和轻量动作。
    </TxPopover>

    <TxTabs v-model="active" placement="left" indicator-variant="pill">
      <TxTabItem name="总览" activation>总览配置</TxTabItem>
      <TxTabItem name="发布">发布配置</TxTabItem>
    </TxTabs>

    <TxDrawer v-model:visible="drawerVisible" title="发布策略" />
  </template>
---
:::

### 最佳实践

- 只放短命令；需要段落、表单或多步交互时改用 `TxPopover`、`TxDrawer` 或 `TxContextMenuPanel`。
- `danger` 只用于破坏性命令；列表变长时与普通命令分组。
- `arrow` 只用于导航或子菜单行；外链图标、快捷键、状态徽标放 `right` 插槽。
- `closeOnSelect=false` 只用于会打开另一层浮层或进入多步流程的行；宿主已有更强反馈或需要同步回调时才关闭 `activationFeedback`。
- 只在宿主打开后自行落焦（如面板内的搜索框）时设 `initialFocus="none"`，否则键盘用户要多按一次方向键才能进入列表。

## API 参考

### TxDropdownMenu

#### 属性

| 属性名 | 类型 | 默认值 | 说明 |
|------|------|---------|------|
| `modelValue` | `boolean` | `undefined` | 打开状态（`v-model`）；省略时非受控。 |
| `trigger` | `'click' \| 'hover'` | `'click'` | 触发方式；`hover` 的延迟与互斥由 `TxPopover` 统一处理。 |
| `placement` | `DropdownPlacement` | `'bottom-start'` | 面板相对触发器的位置。 |
| `offset` | `number` | `6` | 触发器与面板的距离（px）。 |
| `closeOnSelect` | `boolean` | `true` | 可用项触发 `select` 后关闭菜单。 |
| `activationFeedback` | `boolean` | `true` | 关闭前先清空、再确认高亮，各 90ms；减少动态效果时跳过。 |
| `initialFocus` | `'first-item' \| 'none'` | `'first-item'` | 打开时的焦点落点；`'none'` 不移动焦点，由宿主落焦。 |
| `animation` | `BaseAnchorAnimationOptions` | `{}` | 面板动画；空对象使用 BaseAnchor 默认动画。 |
| `minWidth` | `number` | `220` | 面板最小宽度（px）；最大宽度固定为 360px。 |
| `maxHeight` | `number` | `420` | 面板最大高度（px），超出时滚动。 |
| `unlimitedHeight` | `boolean` | `false` | 不限制面板高度。 |
| `referenceClass` | `BaseAnchorClassValue` | - | 追加到触发锚点的 class。 |
| `panelCard` | `BaseAnchorPanelCardProps` | - | 透传给面板卡片的参数。 |
| `panelVariant` | `'solid' \| 'dashed' \| 'plain'` | `'solid'` | 面板边框样式。 |
| `panelBackground` | `'pure' \| 'mask' \| 'blur' \| 'glass' \| 'refraction'` | `'refraction'` | 面板背景效果。 |
| `panelShadow` | `'none' \| 'soft' \| 'medium'` | `'soft'` | 面板阴影。 |
| `panelRadius` | `number` | `18` | 面板圆角（px）。 |
| `panelPadding` | `number` | `8` | 面板内边距（px）。 |

#### 事件

| 事件名 | 参数 | 说明 |
|------|------|------|
| `update:modelValue` | `(value: boolean)` | 请求改变打开状态时触发。 |
| `open` | - | 请求打开时触发。 |
| `close` | - | 请求关闭时触发。 |

#### 插槽

| 插槽名 | 参数 | 说明 |
|------|------|------|
| `trigger` | - | 触发内容，作为 Popover 的 reference。 |
| `default` | - | 菜单行，通常是 `TxDropdownItem`。 |

### TxDropdownItem

#### 属性

| 属性名 | 类型 | 默认值 | 说明 |
|------|------|---------|------|
| `disabled` | `boolean` | `false` | 禁止选中，也不关闭菜单。 |
| `danger` | `boolean` | `false` | 危险操作文字样式。 |
| `arrow` | `boolean` | `false` | 没有 `right` 插槽时显示右侧箭头。 |
| `closeOnSelect` | `boolean` | `undefined` | 逐项覆盖菜单级 `closeOnSelect`。 |
| `activationFeedback` | `boolean` | `undefined` | 逐项覆盖菜单级确认反馈。 |

#### 事件

| 事件名 | 参数 | 说明 |
|------|------|------|
| `select` | - | 选中时触发，不带参数；带确认反馈的关闭项在 180ms 确认后触发。 |

#### 插槽

| 插槽名 | 参数 | 说明 |
|------|------|------|
| `default` | - | 主标签。 |
| `right` | - | 替换 `arrow` 生成的右侧箭头。 |

### TxDropdownSubmenu

#### 属性

| 属性名 | 类型 | 默认值 | 说明 |
|------|------|---------|------|
| `disabled` | `boolean` | `false` | 禁用触发行，子面板不再展开。 |
| `placement` | `DropdownPlacement` | `'right-start'` | 子面板相对触发行的位置。 |
| `offset` | `number` | `4` | 触发行与子面板的距离（px）。 |
| `width` | `number` | `0` | 子面板固定宽度；`0` 按内容与 `minWidth` 自适应。 |
| `minWidth` | `number` | `160` | 子面板最小宽度（px）。 |
| `maxHeight` | `number` | `420` | 子面板最大高度（px），超出时滚动。 |
| `unlimitedHeight` | `boolean` | `false` | 不限制子面板高度。 |
| `animation` | `BaseAnchorAnimationOptions` | `{}` | 子面板动画。 |
| `panelCard` | `BaseAnchorPanelCardProps` | - | 透传给子面板卡片的参数。 |
| `panelVariant` | `'solid' \| 'dashed' \| 'plain'` | `'solid'` | 子面板边框样式。 |
| `panelBackground` | `'pure' \| 'mask' \| 'blur' \| 'glass' \| 'refraction'` | `'refraction'` | 子面板背景效果。 |
| `panelShadow` | `'none' \| 'soft' \| 'medium'` | `'soft'` | 子面板阴影。 |
| `panelRadius` | `number` | `14` | 子面板圆角（px）。 |
| `panelPadding` | `number` | `6` | 子面板内边距（px）。 |

#### 插槽

| 插槽名 | 参数 | 说明 |
|------|------|------|
| `default` | - | 触发行标签。 |
| `right` | - | 触发行右侧信息，位于箭头之前。 |
| `menu` | - | 子面板内容，可再嵌套 `TxDropdownSubmenu`。 |

## 概述

- 包装 `TxPopover`：定位、高度限制、面板卡片与动画遵循同一套锚点行为。
- 会关闭菜单的选中先清空高亮、再以 `TxCardItem` 激活态确认，然后派发 `select` 并关闭；其余选中立即派发。禁用项不选中也不关闭。
- 面板是 `role="menu"`，条目是 `role="menuitem"`；打开时聚焦首个可用项，`initialFocus="none"` 跳过这一步。
- 键盘：`ArrowDown` / `ArrowUp` 循环移动，也能从搜索框进入列表；`Home` / `End` 跳到首末项，焦点在 `input`、`textarea` 或 `contenteditable` 内时留给光标。
- 子菜单：触发行 `ArrowRight` / `Enter` 展开并聚焦首项，子面板内 `ArrowLeft` 收回；子项按根菜单的 `closeOnSelect` 关闭整条链；点击子面板不算外部点击，父层关闭时级联关闭。
- 悬停桥覆盖父子面板之间 4px 的间隙；斜向经过的兄弟子菜单行不展开，停留约 100ms 才切换。

## 技术实现

- 确认反馈由 `packages/tuffex/packages/utils/menu-activation-feedback.ts` 驱动，与 ContextMenu 共用。
- 源码：`packages/tuffex/packages/components/src/dropdown-menu/`。

<TuffDocSourceLink />
