news 2026/9/8 22:06:51

Ant Design Dropdown 可选中菜单实战:通过 `menu.selectable` 开启下拉项选择能力

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Ant Design Dropdown 可选中菜单实战:通过 `menu.selectable` 开启下拉项选择能力

Ant Design Dropdown 可选中菜单实战:通过menu.selectable开启下拉项选择能力

【免费下载链接】ant-designAn enterprise-class UI design language and React UI library项目地址: https://gitcode.com/GitHub_Trending/an/ant-design

Dropdown(下拉菜单)在 Ant Design 中常用于"多个选项择一执行"的场景,而官方文档给出的这一则示例正是它的一个重要进阶用法:让下拉菜单里的选项具备"选中"能力。本指南以 components/dropdown/demo/selectable.md 及其配套示例为核心,讲解如何开启选择态、相关 MenuProps 字段的配合方式,并结合 dropdown 源码 揭示选中后下拉面板自动收起与否的真实逻辑。读完你可以直接在自己的 Dropdown 中实现单选、多选与受控选中三种形态。

示例要解决的问题:让下拉菜单项"可以被选中"

官方 Demo 的说明非常简洁,原文如下:

zh-CN:添加menu中的selectable属性可以开启选择能力。 en-US:Configure theselectableproperty inmenuto enable selectable ability.

翻译成实际效果就是:Dropdown 默认只负责"弹出菜单、点击执行动作",菜单项并不会停留在"被选中"的高亮/勾选状态;只要你在 Dropdown 的menu配置对象里显式打开selectable: true,菜单项就会进入可选择模式,被点击的项会呈现选中态。这与导航型Menu中管理当前激活项是同一套状态体系,只是入口被搬到了 Dropdown 的menu属性上。

示例的可运行代码位于 components/dropdown/demo/selectable.tsx,同时这段示例也以 "Selectable Menu" 的标题挂在 Dropdown 官方 API 文档 的示例列表中(见该文档第 34 行)。

完整示例拆解:逐字段看懂最小可用写法

下面把示例代码完整还原并加上注释:

import React from 'react'; import { DownOutlined } from '@ant-design/icons'; import type { MenuProps } from 'antd'; import { Dropdown, Space, Typography } from 'antd'; const items: MenuProps['items'] = [ { key: '1', label: 'Item 1' }, { key: '2', label: 'Item 2' }, { key: '3', label: 'Item 3' }, ]; const App: React.FC = () => ( <Dropdown menu={{ items, selectable: true, // 关键开关:开启菜单项选择能力 defaultSelectedKeys: ['3'], // 初始即让 key 为 '3' 的菜单项处于选中态 }} > {/* 触发元素:整行都是可点击的下拉触发器 */} <Typography.Link> <Space> Selectable <DownOutlined /> {/* 经典的“下箭头”下拉指示图标 */} </Space> </Typography.Link> </Dropdown> ); export default App;

这个例子只动用了三个要点,就可以直接跑通"可选中下拉":

  • menu.items:以对象数组(MenuProps['items'])声明菜单项。每个菜单项必须有唯一的key,因为选择状态(selected keys)正是以 key 为维度进行维护的;
  • menu.selectable:置为true,菜单项可被选中,被点中的项会出现选中态样式;
  • menu.defaultSelectedKeys:非受控场景下声明"哪些 key 默认处于选中态"。这里传['3'],所以面板第一次打开时第 3 项就已经是勾选状态。

需要说明的是,Dropdown自身并没有一个叫selectable的属性——选择能力完全来自其menu属性。从 dropdown.tsx 的类型定义可以看到,menu的类型就是完整的 MenuProps:

// components/dropdown/dropdown.tsx menu?: MenuProps & { activeKey?: RcMenuProps['activeKey'] };

同时该文件顶部import type { MenuProps } from '../menu'(见 dropdown.tsx),说明 Dropdown 的下拉菜单底层复用的就是 Menu 组件,凡是 Menu 支持的选择类能力,Dropdown 的menu配置里都能用。

与选择能力相关的 MenuProps 字段全家桶

要发挥selectable的完整价值,通常需要和下面几个 MenuProps 字段配合。它们既适用于独立 Menu,也适用于 Dropdown 的menu配置:

字段类型作用
selectableboolean是否开启菜单项选择能力,true时被点击项显示选中态
multipleboolean是否允许多选(需与selectable同开才有意义)
defaultSelectedKeysstring[]非受控:设置初始选中项集合
selectedKeysstring[]受控:由外部状态决定当前选中项集合
onSelect({ key, ... }) => void用户新选中某项时触发的回调
onDeselect({ key, ... }) => void用户取消选中某项时触发(多选场景)

配合思路可以总结为两条使用路径:

  • 非受控(最简单):只声明selectable+defaultSelectedKeys,让 Menu 自己维护内部选中状态,例如示例中defaultSelectedKeys: ['3']的用法。适合只需要“开启选中交互、不必把选择结果同步给业务代码”的场景。
  • 受控(需要回读选中值):同时声明selectable+selectedKeys,并在onSelect/onDeselect中更新外部 state。此时选中的真正“事实来源”在业务侧,适合需要把当前选中项上报、存储或影响其他 UI 的场景。

仓库中另一个配套示例 components/dropdown/demo/selection.tsx(在 API 文档 中以 "Selection actions" 命名)正是在此基础上的延伸演示,展示了选中动作与业务逻辑联动时的典型写法,建议对照阅读。

源码视角:下拉面板里的 Menu 是如何被组装出来的

要理解selectable为什么放在menu里就能生效,可以看 dropdown.tsx 中renderOverlay的实现:当用户提供了menu.items时,Dropdown 会把整个menu对象原样展开渲染成一个真正的Menu组件:

// components/dropdown/dropdown.tsx(renderOverlay 内部,节选) if (menu?.items) { overlayNode = ( <Menu {...menu} ... /> ); }

也就是说,selectabledefaultSelectedKeys这些字段最终是被透传给了内部的标准 Menu。同时,这段 Menu 又被一个OverrideProvider包裹,其中强制约定了几条下拉菜单的默认行为(见 dropdown.tsx):

<OverrideProvider prefixCls={`${prefixCls}-menu`} ... mode="vertical" // 下拉菜单固定为垂直排布 selectable={false} // 默认关闭可选中,需要用户主动在 menu.selectable 中打开 onClick={onMenuClick} ... >

这一小段代码正好印证了官方示例文案里的两句话:

  1. 为什么需要“添加selectable属性”才能开启?因为 OverrideProvider 给下拉内部菜单的默认值就是selectable: false,示例显式传入selectable: true即是对默认值的覆盖,符合直觉;
  2. mode="vertical"说明下拉菜单内部始终以垂直模式渲染,因此你不需要、也不应该在 Dropdown 的菜单上自行指定其他mode

一个易被忽略的行为:选中后面板会不会自动收起?

选择能力与“点击菜单项后面板关闭”的默认交互会发生叠加,处理逻辑在 dropdown.tsx 的onMenuClick中:

const onMenuClick = useEvent(() => { if (menu?.selectable && menu?.multiple) { return; // 可选中且为多选:点完不收起,方便连续勾选 } onOpenChange?.(false, { source: 'menu' }); setOpen(false); // 否则:点击菜单项后自动收起 });

由此可以归纳出官方刻意设计的两套行为,这也是实测中最容易踩坑的点:

  • 单选场景(selectable: true,未开multiple:用户点击某个菜单项后,下拉面板会照常自动收起,配合触发元素上的onOpenChangeonSelect即可完成“选一个、关面板、拿到值”的完整闭环,这也是最常见的用法;
  • 多选场景(selectable: true+multiple: true:面板不会自动收起,用户可以连续点选/取消多个选项,选完后再点击面板外部将其关闭。如果此时你期待“每点一项就自动收起”,将会发现行为与预期不同——这正是上面这段源码想表达的判断条件。

从单选到多选:一个可直接落地的进阶示例

基于同一套字段,开启多选只需要额外加上multiple: true,并配合受控的selectedKeys读取结果:

import React, { useState } from 'react'; import { DownOutlined } from '@ant-design/icons'; import type { MenuProps } from 'antd'; import { Dropdown, Space, Typography } from 'antd'; const items: MenuProps['items'] = [ { key: 'a', label: 'React' }, { key: 'b', label: 'Vue' }, { key: 'c', label: 'Svelte' }, ]; const App: React.FC = () => { const [selectedKeys, setSelectedKeys] = useState<string[]>(['a']); const menuProps: MenuProps = { items, selectable: true, multiple: true, selectedKeys, onSelect: ({ key }) => setSelectedKeys((prev) => [...prev, key]), onDeselect: ({ key }) => setSelectedKeys((prev) => prev.filter((k) => k !== key)), }; return ( <Dropdown menu={menuProps} trigger={['click']}> <Typography.Link> <Space> 已选 {selectedKeys.length} 项:{selectedKeys.join(', ')} </Space> <DownOutlined /> </Typography.Link> </Dropdown> ); }; export default App;

注意此处由于是multiple模式,依据上文源码逻辑,点击项后面板不会收起,用户可以通过点击空白区域关闭。若你希望选中某个值后立即把结果汇报出去并关闭面板,则应采用单选(去掉multiple)并用onSelect同步状态。

使用要点与避坑清单

  1. key必须唯一且稳定:选择状态、展开状态都以 key 索引,重复 key 会导致勾选与事件错乱;
  2. 先开selectable,再谈defaultSelectedKeys/selectedKeys:不开selectable时,即便传入选中 key,菜单项也不会进入可选择/勾选的可视状态;
  3. 单选默认自动收起,多选默认不收起:这是 dropdown.tsx 中selectable && multiple判断直接决定的,不要依赖直觉猜测,需要保持展开请走多选分支;
  4. 触发元素需要支持事件冒泡:Dropdown 依赖子节点响应onMouseEnteronMouseLeaveonFocusonClick(见 API 文档 的 Note 一节),使用Typography.Link等标准元素即可,自定义组件需确保这些事件能正常触发;
  5. 区分非受控与受控:演示类代码常用defaultSelectedKeys省事,业务中需要回读选中值时,请切换为selectedKeys+onSelect/onDeselect的受控写法。

相关阅读

  • 示例描述文档:components/dropdown/demo/selectable.md
  • 示例实现代码:components/dropdown/demo/selectable.tsx
  • 选择动作进阶示例:components/dropdown/demo/selection.tsx
  • Dropdown 核心实现(renderOverlayOverrideProvideronMenuClick):components/dropdown/dropdown.tsx
  • Menu 上下文覆盖逻辑(selectable默认值来源):components/menu/OverrideContext.tsx
  • Dropdown 完整 API 与全部示例索引:components/dropdown/index.en-US.md

【免费下载链接】ant-designAn enterprise-class UI design language and React UI library项目地址: https://gitcode.com/GitHub_Trending/an/ant-design

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/8 22:06:41

技术博文生成的前提条件与规范要求

简介&#xff1a;本资源是一个面向结构优化研究者与工程仿真工程师的MATLAB拓扑优化工具包&#xff0c;聚焦移动渐近线法&#xff08;MMC&#xff09;在轻量化设计中的实践应用&#xff0c;适用于航空航天、汽车底盘及土木结构等领域的性能提升需求。压缩包为4KB的ZIP文件&…

作者头像 李华
网站建设 2026/9/8 22:04:48

在PC上跑起PS3游戏前,RPCS3需要先确认这4件事

在PC上跑起PS3游戏前&#xff0c;RPCS3需要先确认这4件事 【免费下载链接】rpcs3 PlayStation 3 emulator and debugger 项目地址: https://gitcode.com/GitHub_Trending/rp/rpcs3 RPCS3是一个用C编写的开源PlayStation 3模拟器&#xff0c;支持Windows、Linux和macOS&a…

作者头像 李华
网站建设 2026/9/8 22:04:27

RPCS3 安装教程:三平台 PS3 模拟器从下载到出画面的完整路径

RPCS3 安装教程&#xff1a;三平台 PS3 模拟器从下载到出画面的完整路径 【免费下载链接】rpcs3 PlayStation 3 emulator and debugger 项目地址: https://gitcode.com/GitHub_Trending/rp/rpcs3 想在电脑上玩《战神》或《地平线&#xff1a;零之曙光》&#xff0c;开源…

作者头像 李华
网站建设 2026/9/8 22:03:34

AWS全场景安全运营体系搭建:Web/APP/IoT告警降噪与自动化响应

如果你手上同时管着Web门户、移动App和一批IoT设备&#xff0c;那么AWS云环境的安全运营往往不是“有没有安全工具”的问题&#xff0c;而是“工具散落一地、告警互相打架、出了事不知道先看哪块”的问题。最近我帮一家客户从0到1搭了一套覆盖Web/APP/IoT全场景的AWS安全运营体…

作者头像 李华
网站建设 2026/9/8 22:03:33

鸟类目标检测数据集:VOC+YOLO双格式16283张图实战指南

简介&#xff1a;本资源为面向计算机视觉初学者与算法工程师的鸟类目标检测专用数据集&#xff0c;覆盖10种常见亚洲鸟类&#xff0c;适用于YOLO系列、Faster R-CNN等主流检测模型的训练与验证。数据集同时提供Pascal VOC格式&#xff08;含16283个XML标注文件&#xff09;与YO…

作者头像 李华