ant-design AutoComplete 自动完成组件深度解析:从 API 全量参数到 Select Combobox 底层实现
本文基于 ant-design 仓库中的 AutoComplete 组件文档,系统讲解自动完成组件的适用场景、全部 API 参数与事件回调、查询模式实战写法,并结合 AutoComplete 源码 剖析其“本质上是 Select 的 combobox 模式”这一底层设计。读完本文,你可以独立完成邮箱补全、搜索建议、分组类目查询等常见录入场景,并理解 options/showSearch/classNames 等配置项在源码中的真实生效路径。
何时使用:AutoComplete 与 Select 的本质区别
文档给出的使用边界非常明确——当你需要一个输入框而不是选择器,或者需要输入建议/辅助提示时,才应该使用 AutoComplete。它与 Select 的区别在于设计意图:
- AutoComplete 是一个带提示的文本输入框,用户可以自由输入,关键词是辅助输入;
- Select 是在限定的可选项中进行选择,关键词是选择。
从源码结构看,这个定位直接体现在实现方式上:AutoComplete.tsx 并没有独立实现一套下拉逻辑,而是在第 263~288 行直接渲染 <Select>,并传入内部常量:
mode={Select.SECRET_COMBOBOX_MODE_DO_NOT_USE as SelectProps['mode']}
在 Select 组件 中,该常量会被映射为 rc-select 的 'combobox' 模式:
if (m === SECRET_COMBOBOX_MODE_DO_NOT_USE) {
return 'combobox';
}
也就是说,AutoComplete 是 Select 在 combobox 模式下的受控封装,下拉面板、虚拟滚动、键盘导航、焦点管理等能力全部复用自 Select。这一点也解释了为什么它的主题 Token 文档直接引用 Select 的 Token 表(原文档中 <ComponentTokenTable component="Select">)。
代码演示:覆盖文档中的全部实战场景
文档共提供 10 个正式 demo 和 7 个 Debug 场景。以下按文档顺序逐一讲解关键场景的核心代码,代码均可在 demo 目录 中找到对应文件。
1. 基本使用:onSearch 驱动 options
基本用法的核心是通过 showSearch.onSearch 在用户输入时更新 options(见 basic.tsx):
import { AutoComplete } from 'antd';
import type { AutoCompleteProps } from 'antd';
const mockVal = (str: string, repeat = 1) => ({
value: str.repeat(repeat),
});
const App = () => {
const [value, setValue] = useState('');
const [options, setOptions] = useState<AutoCompleteProps['options']>([]);
const getPanelValue = (searchText: string) =>
!searchText ? [] : [mockVal(searchText), mockVal(searchText, 2), mockVal(searchText, 3)];
return (
<>
<AutoComplete
options={options}
style={{ width: 200 }}
showSearch={{
onSearch: (text) => setOptions(getPanelValue(text)),
}}
placeholder="input here"
/>
<br />
<br />
{/* 受控模式:value + onChange */}
<AutoComplete
value={value}
showSearch={{ onSearch: (text) => setOptions(getPanelValue(text)) }}
options={options}
style={{ width: 200 }}
onChange={(data) => setValue(data)}
placeholder="control mode"
/>
</>
);
};
注意受控示例中用 onChange 管理 value,而不是 onSearch,这一点与文末 FAQ 中“受控状态下请勿用 onSearch 管理中文输入”的结论一致。
2. 自定义选项:邮箱补全
options 支持 label 与 value 分离的数据化配置,相比 jsx 定义渲染性能更好。以邮箱补全为例(见 options.tsx):
const [options, setOptions] = React.useState<AutoCompleteProps['options']>([]);
const handleSearch = (value: string) => {
setOptions(() => {
if (!value || value.includes('@')) {
return [];
}
return ['gmail.com', '163.com', 'qq.com'].map((domain) => ({
label: `${value}@${domain}`,
value: `${value}@${domain}`,
}));
});
};
return (
<AutoComplete
style={{ width: 200 }}
showSearch={{ onSearch: handleSearch }}
placeholder="input here"
options={options}
/>
);
当输入包含 @ 后返回空数组,下拉自动收起——这正是 FAQ 中“options 为空时不展示下拉菜单”行为的典型应用。
3. 自定义输入组件
通过 children 传入自定义输入框(类型限定为 HTMLInputElement | HTMLTextAreaElement | <InputProps 的 ReactElement>,默认 <Input />)。custom.tsx 展示了用 TextArea 替换默认输入框的写法:
<AutoComplete options={options} style={{ width: 200 }} onSelect={onSelect}
showSearch={{ onSearch: handleSearch }}>
<TextArea
placeholder="input here"
className="custom"
style={{ height: 50 }}
onKeyPress={handleKeyPress}
/>
</AutoComplete>
源码中 AutoComplete.tsx 第 132~143 行 对 children 做了甄别:当 children 是唯一元素且不是 Select.Option/OptGroup 时,才会被识别为自定义输入组件,并通过内部 API getInputElement 透传给 Select。同时源码在开发环境下有一条 warning:使用自定义输入组件时不应再设置 size,需要自行控制尺寸样式。
4. 不区分大小写:showSearch.filterOption
筛选逻辑挂在 showSearch.filterOption 上,函数接收 inputValue 与 option 两个参数(见 non-case-sensitive.tsx):
<AutoComplete
style={{ width: 200 }}
options={options}
placeholder="try to type `b`"
showSearch={{
filterOption: (inputValue, option) =>
option!.value.toUpperCase().includes(inputValue.toUpperCase()),
}}
/>
需要特别注意:顶层的 filterOption、onSearch、dataSource 等均已废弃(见下文 API 表),筛选相关能力统一收敛到 showSearch 对象中。
5. 查询模式:确定类目与不确定类目
这是文档中最贴近真实业务的两组 demo。
确定类目(certain-category.tsx):options 支持二级结构,第一层是带 label + options 的分组标题,常用于搜索结果按 Libraries/Solutions/Articles 等类目展示,并配合 Input.Search 作为自定义输入组件:
const options = [
{
label: <Title title="Libraries" />,
options: [renderItem('AntDesign', 10000), renderItem('AntDesign UI', 10600)],
},
{
label: <Title title="Solutions" />,
options: [renderItem('AntDesign UI FAQ', 60100), renderItem('AntDesign FAQ', 30010)],
},
// ...
];
<AutoComplete
classNames={{ popup: { root: styles.categorySearch } }}
popupMatchSelectWidth={500}
style={{ width: 250 }}
options={options}
>
<Input.Search size="large" placeholder="input here" />
</AutoComplete>
注意这里 popupMatchSelectWidth 传入了数字 500,即下拉菜单最小宽度固定为 500px,允许内容比输入框更宽。
不确定类目(uncertain-category.tsx):搜索结果数量未知,onSearch 返回带链接和结果数的扁平选项列表,输入框使用带按钮的 Input.Search:
<AutoComplete
popupMatchSelectWidth={252}
style={{ width: 300 }}
options={options}
onSelect={onSelect}
showSearch={{ onSearch: handleSearch }}>
<Input.Search size="large" placeholder="input here" enterButton />
</AutoComplete>
6. 其他正式场景速览
- 自定义状态(status.tsx):
status="error"/status="warning"设置校验态边框与提示样式; - 多种形态(variant.tsx,5.13.0 起):
variant支持outlined(默认)/borderless/filled/underlined; - 自定义清除按钮(allowClear.tsx):
allowClear自 5.8.0 起支持对象形式allowClear={{ clearIcon: <CloseSquareFilled /> }}替换默认清除图标; - 自定义语义结构的样式和类(style-class.tsx,6.0.0 起):通过
classNames/styles精确定位root、input、popup等语义节点。
7. Debug 场景
文档还列出了 7 个 debug demo,用于回归验证特定缺陷修复,包括自定义输入组件配合清除按钮、禁用自定义输入、Form 中的禁用文字颜色、填充形态自定义输入、Form 集成,以及 AutoComplete._InternalPanelDoNotUseOrYouWillBeFired 静态面板(见 render-panel.tsx)。该静态面板在 index.tsx 中由 genPurePanel 生成,命名中的 “DoNotUse” 提示它仅用于调试预览,不建议在业务中使用。
完整 API 参考
通用属性参考:通用属性。
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|---|---|---|---|---|
| allowClear | 支持清除 | boolean | { clearIcon?: ReactNode } | false | 5.8.0: 支持对象形式 |
| backfill | 使用键盘选择选项的时候把选中项回填到输入框中 | boolean | false | |
| children | 自定义输入框 | HTMLInputElement | HTMLTextAreaElement | React.ReactElement<InputProps> | <Input /> | |
| classNames | 用于自定义组件内部各语义化结构的 class,支持对象或函数 | Record<SemanticDOM, string> | (info: { props })=> Record<SemanticDOM, string> | - | |
自动完成的数据源,请使用 options 替代 |
DataSourceItemType[] | - | - | |
| defaultActiveFirstOption | 是否默认高亮第一个选项 | boolean | true | |
| defaultOpen | 是否默认展开下拉菜单 | boolean | - | |
| defaultValue | 指定默认选中的条目 | string | - | |
| disabled | 是否禁用 | boolean | false | |
下拉菜单的 className 属性,请使用 classNames.popup.root 替代 |
string | - | - | |
下拉菜单和输入框是否同宽,请使用 popupMatchSelectWidth 替代 |
boolean | number | true | - | |
自定义下拉框内容,使用 popupRender 替换 |
(originNode: ReactElement) => ReactNode | - | 4.24.0 | |
| popupRender | 自定义下拉框内容 | (originNode: ReactElement) => ReactNode | - | |
下拉菜单的 className 属性,使用 classNames.popup.root 替换 |
string | - | 4.23.0 | |
下拉菜单的 style 属性,使用 styles.popup.root 替换 |
CSSProperties | - | ||
| popupMatchSelectWidth | 下拉菜单和选择器同宽。默认将设置 min-width,当值小于选择框宽度时会被忽略。false 时会关闭虚拟滚动 |
boolean | number | true | |
是否根据输入项进行筛选。当其为一个函数时,会接收 inputValue、option 两个参数 |
boolean | function(inputValue, option) | true | ||
| getPopupContainer | 菜单渲染父节点。默认渲染到 body 上,如果你遇到菜单滚动定位问题,试试修改为滚动的区域,并相对其定位 | function(triggerNode) | () => document.body | |
| notFoundContent | 当下拉列表为空时显示的内容 | ReactNode | - | |
| open | 是否展开下拉菜单 | boolean | - | |
| options | 数据化配置选项内容,相比 jsx 定义会获得更好的渲染性能 | { label, value }[] | - | |
| placeholder | 输入框提示 | string | - | |
| showSearch | 搜索配置 | true | Object | true | |
| status | 设置校验状态 | 'error' | 'warning' | - | 4.19.0 |
| size | 控件大小 | large | medium | small |
- | |
| styles | 用于自定义组件内部各语义化结构的行内 style,支持对象或函数 | Record<SemanticDOM, CSSProperties> | (info: { props })=> Record<SemanticDOM, CSSProperties> | - | |
| value | 指定当前选中的条目 | string | - | |
| variant | 形态变体 | outlined | borderless | filled | underlined |
outlined |
5.13.0 |
| virtual | 设置 false 时关闭虚拟滚动 | boolean | true | 4.1.0 |
| onBlur | 失去焦点时的回调 | function() | - | |
| onChange | 选中 option,或 input 的 value 变化时,调用此函数 | function(value) | - | |
展开下拉菜单的回调,使用 onOpenChange 替换 |
(open: boolean) => void | |||
| onOpenChange | 展开下拉菜单的回调 | (open: boolean) => void | - | |
| onFocus | 获得焦点时的回调 | function() | - | |
| 搜索补全项的时候调用 | function(value) | - | ||
| onSelect | 被选中时调用,参数为选中项的 value 值 | function(value, option) | - | |
| onClear | 清除内容时的回调 | function | - | 4.6.0 |
| onInputKeyDown | 按键按下时回调 | (event: KeyboardEvent) => void | - | |
| onPopupScroll | 下拉列表滚动时的回调 | (event: UIEvent) => void | - |
废弃属性的源码级迁移对照
上表中的废弃项并非只是文档约定,源码 AutoComplete.tsx 第 188~200 行 在开发环境下会对它们逐条触发 deprecation warning,并内置了官方迁移映射:
| 废弃属性 | 替代方案(源码 deprecatedProps 映射) |
|---|---|
| dropdownMatchSelectWidth | popupMatchSelectWidth |
| dropdownStyle | styles.popup.root |
| dropdownClassName / popupClassName | classNames.popup.root |
| dropdownRender | popupRender |
| onDropdownVisibleChange | onOpenChange |
| dataSource | options |
对于 dataSource,源码还保留了向后兼容的转换逻辑(第 148~177 行):字符串会被转换为 <Option value={item}>{item}</Option>,{ value, text } 对象则以 text 作为选项展示文本。新代码建议直接使用 options。
showSearch
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|---|---|---|---|---|
| filterOption | 是否根据输入项进行筛选。函数形式接收 inputValue、option,符合筛选条件返回 true |
boolean | function(inputValue, option) | true | |
| onSearch | 搜索补全项的时候调用 | function(value) | - |
类型定义上(AutoComplete.tsx 第 91~96 行),showSearch 除了 boolean 外,可传入 SearchConfig 中 filterOption、onSearch、searchIcon 三个字段,与 demo 中 showSearch={{ onSearch: ... }} 的写法完全对应。
方法
通过 ref 获取实例后可调用:
| 名称 | 描述 |
|---|---|
| blur() | 移除焦点 |
| focus() | 获取焦点 |
由于组件类型签名为 React.RefAttributes<BaseSelectRef>(AutoComplete.tsx 第 291~301 行),其 ref 实际是 Select 的 BaseSelectRef,因此 Select ref 上的常用能力同样可用。
Semantic DOM 与语义化样式
classNames 与 styles 支持的语义节点定义在 AutoComplete.tsx 第 23~40 行 的 AutoCompleteSemanticType:
root:组件根节点,自动附加{prefixCls}-auto-complete类,使用自定义输入组件时还会附加{prefixCls}-customize类;prefix:前缀区域;input:输入框;placeholder:占位符;content:内容区;popup.root/popup.list/popup.listItem:下拉层及其内部列表、列表项。
其中 popup.root 会合并旧版 popupClassName、dropdownClassName(见 finalClassNames 逻辑),这正是“旧属性迁移到 classNames.popup.root”得以平滑过渡的实现细节。完整节点示例可参考 _semantic.tsx demo。
主题变量(Design Token)
AutoComplete 复用 Select 的设计 Token,配置方式与 Select 组件 相同,通过 ConfigProvider 的 theme.components.Select 调整。Token 明细请直接查阅文档中的 Select Token 表(原文档以 <ComponentTokenTable component="Select"> 渲染),仓库中相关 Token 生成脚本见 generate-token-meta.ts。
FAQ
为何受控状态下使用 onSearch 无法输入中文?
请使用 onChange 进行受控管理。onSearch 触发于搜索输入,与 onChange 时机不同。此外,点击选项时也不会触发 onSearch 事件。中文输入走 IME 组合事件,onSearch 的组合(composition)期间不触发,导致受控值无法随拼音输入更新,而 onChange 的处理时机覆盖了这一过程。
为何 options 为空时,受控 open 展开不会显示下拉菜单?
AutoComplete 组件本质上是 Input 输入框的一种扩展,当 options 为空时,显示空文本会让用户误以为该组件不可操作,实际上它仍然可以进行文本输入操作。因此,为了避免给用户带来困惑,当 options 为空时,open 属性为 true 也不会展示下拉菜单,需要与 options 属性配合使用。
小结
AutoComplete 在 ant-design 中的实现策略可以概括为:API 面向输入框心智,实现复用 Select 的 combobox 能力。掌握三个要点即可驾驭该组件:一是用 showSearch(而非已废弃的顶层 filterOption/onSearch)控制筛选与搜索回调;二是优先用 options 数据化配置替代 jsx children 和 dataSource,以换取渲染性能和更好的维护性;三是通过 classNames/styles 的语义节点精确介入外观,替代零散的 dropdownClassName 等旧属性。遇到行为疑点时,可直接对照 AutoComplete 源码 与 Select 源码 中的属性合并逻辑快速定位。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00