
Semi Design AutoComplete 自动完成组件实战指南从输入建议到源码原理【免费下载链接】semi-designA modern, comprehensive, flexible design system and React UI library, AI-friendly built-in.Provide 3000 Design Tokens, easy to build your design system. Make Semi Design to Any Design. Design to Code in one click项目地址: https://gitcode.com/gh_mirrors/se/semi-designAutoComplete 是 Semi Design 提供的输入建议自动补全组件它本质上是增强版的 Input——用户既可以自由输入任意内容也可以在输入过程中获得候选项建议并快速选择。本文以 content/input/autocomplete/index.md 为骨架结合 packages/semi-ui/autoComplete 与 packages/semi-foundation/autoComplete 的源码实现系统讲解 AutoComplete 的使用场景、数据驱动方式、全部 API 参数、键盘可访问性并深入剖析其底层 Foundation 状态机与渲染链路帮助你在项目中正确选型并把它用到极致。使用场景与选型判断AutoComplete 用于对输入框提供输入建议进行自动补全的操作。典型场景包括邮箱域名补全用户输入前缀后给出gmail.com、163.com等候选域名搜索联想根据用户已输入的关键词实时请求后端接口返回联想词列表表单录入辅助在姓名、邮箱、标签等字段中为用户提供可选的规范化输入。与可搜索 Select 的本质区别AutoComplete 常被拿来与支持搜索的 Select 组件对比文档明确指出了三点核心差异对比维度AutoComplete可搜索 Select组件本质增强型的、提供了输入建议的Input一个选择器点击展开时的行为保留上次选中的值将输入框的值全部清空已选项渲染renderSelectedItem只允许返回字符串可定制化程度更高可为任意类型的 ReactNode这一点在 packages/semi-ui/autoComplete/index.tsx 的组件注释中也有同样的说明AutoComplete 是enhanced Input (candidates suggest that users can choose or not)且由于选中值要直接显示在 Input 中props.value只支持字符串而 Select 的 value 支持传入对象。在 packages/semi-foundation/autoComplete/foundation.ts 中选中候选项时若配置了renderSelectedItem会执行它并显式校验返回值必须是字符串否则通过warning给出renderSelectedItem must return string的告警。因此选型建议很清晰如果业务要求必须从给定的列表里选一个值用 Select如果业务是用户自由输入 可选建议用 AutoComplete。快速开始引入与基本用法如何引入import { AutoComplete } from douyinfe/semi-ui;基本用法字符串数据源AutoComplete 的核心数据流是通过onSearch监听用户输入将输入建议通过更新props.data传入通过onChange保持受控输入框变化或选中输入项时都会触发onChange。import React from react; import { AutoComplete } from douyinfe/semi-ui; import { IconSearch } from douyinfe/semi-icons; () { const [stringData, setStringData] useState([]); const [value, setValue] useState(); const handleStringSearch (value) { let result; if (value) { result [gmail.com, 163.com, qq.com].map(domain ${value}${domain}); } else { result []; } setStringData(result); }; const handleChange (value) { console.log(onChange, value); setValue(value); }; return ( AutoComplete data{stringData} value{value} showClear prefix{IconSearch /} placeholder搜索... onSearch{handleStringSearch} onChange{handleChange} style{{ width: 200 }} / ); };这个例子揭示了 AutoComplete 与普通 Input 使用体验上的关键差异组件本身不做过滤过滤逻辑完全由onSearch回调交给开发者实现data始终由开发者全量控制。从源码看foundation.ts 的handleSearch依次执行updateInputValue更新输入框、notifySearch触发 onSearch、notifyChange触发 onChange并在面板未打开时自动openDropdown()。而 index.tsx 的componentDidUpdate中一旦检测到props.data变化就会调用handleDataChange重新生成候选项列表并触发rePositionDropdown重新定位浮层。受控与非受控受控同时传入value和onChange如上面的示例非受控只传defaultValue组件内部通过updateInputValue维护自身状态。在 foundation.ts 的init中可以看到初始化规则defaultValue与value同时存在时最终以value为准初始化后通过handleValueChange将值同步到输入框与选中态selection。而handleSelect选中候选项中foundation.ts 区分了受控与非受控受控模式下直接关闭下拉并触发onSelect输入框的值交给外部value控制非受控模式下则先updateInputValue、再updateSelection、触发onSelect、最后关闭下拉。数据源data的两种形态data是候选项的数据源可以有两种形态1. 字符串数组AutoComplete data{[semi, ies, design, platform]} /2. 对象数组自定义候选项渲染的基础当需要自定义候选项渲染时data可以传入一个对象数组每个对象必须含有label、value两个 keyvalue是候选项被选中后写入输入框的值label是候选项在列表中展示的内容。对象还可以携带任意扩展字段供renderItem/renderSelectedItem使用。import React from react; import { AutoComplete, Avatar } from douyinfe/semi-ui; import { IconSearch } from douyinfe/semi-icons; () { const color [amber, indigo, cyan]; const [data, setData] useState([ { name: 夏可漫, email: xiakemanexample.com, abbr: XK, color: amber }, { name: 申悦, email: shenyueexample.com, abbr: SY, color: indigo }, { name: 曲晨一, email: quchenyiexample.com, abbr: CY, color: blue }, { name: 文嘉茂, email: wenjiamaoexample.com, abbr: JM, color: cyan }, ]); const [value, setValue] useState(); const handleStringSearch (value) { let result; if (value) { result data.map(item { return { ...item, value: item.name, label: item.email }; }); } else { result []; } setData(result); }; const renderOption (item) { let optionStyle { display: flex, }; return ( Avatar color{item.color} sizesmall {item.abbr} /Avatar div style{{ marginLeft: 4 }} div style{{ fontSize: 14, marginLeft: 4 }}{item.name}/div div style{{ marginLeft: 4 }}{item.email}/div /div / ); } return ( AutoComplete data{data} showClear prefix{IconSearch /} onSearch{handleStringSearch} renderItem{renderOption} renderSelectedItem{option option.email} style{{ width: 280 }} / ); };从源码看foundation.ts 的_generateList负责把data归一化为内部 option 结构字符串或数字会被转换为{ value, key, label, show: true }对象类型则在value不为 undefined 时展开为{ show: true, ...item }。若传入了renderItem函数则会把渲染结果存入内部属性_renderedLabel供 index.tsx 的renderOption直接使用option._renderedLabel ?? option.label。renderItem 与 renderSelectedItem 的分工renderItem控制下拉列表候选项的渲染签名(option: string | Item) ReactNode可以返回任意 JSXrenderSelectedItem控制候选项被点击选中后在选择框输入框中的渲染内容签名(option: string | Item) string仅支持 String 类型的返回值。另外packages/semi-ui/autoComplete/option.tsx 中还有一个值得注意的实现细节当候选项内容是字符串且存在inputValue时Option 组件会用 packages/semi-ui/highlight 的Highlight组件自动高亮命中的关键词样式类为semi-autocomplete-option-keyword即默认自带输入关键词高亮能力无需额外实现。远程搜索与异步加载远程搜索的核心思路是从onSearch中获取用户输入值动态更新data值并用loading属性控制下拉列表的加载动画。实际项目中通常还会配合防抖debounce来降低请求频率。import React from react; import { AutoComplete } from douyinfe/semi-ui; import { IconSearch } from douyinfe/semi-icons; import { IconSelect, IconForm, IconTable, IconInput, IconButton } from douyinfe/semi-icons-lab; () { let initList [ { value: select, label: 选择器, icon: IconSelect/ }, { value: input, label: 输入框, icon: IconInput/ }, { value: form, label: 表单, icon: IconForm / }, { value: button, label: 按钮, icon: IconButton / }, { value: table, label: 表格, icon: IconTable / }, ]; const [loading, setLoading] useState(false); const [list, setList] useState(initList); const handleSearch (inputValue) { setLoading(true); let newList initList; if (inputValue) { newList list.filter(item item.value.includes(inputValue)); } setTimeout(() { setList(newList); setLoading(false); }, 1000); }; const search debounce(handleSearch, 200); const handleSelect () { console.log(value); }; const renderItem (item) { return ( div style{{ display: flex, alignItems: center }} div style{{ fontSize: 32 }}{item.icon}/div div style{{ marginLeft: 12 }} p{item.value}/p p{item.label}/p /div /div ); }; const renderSelectedItem (item) { // 注意与其他组件如Select不同此处只能返回String类型的值不能返回ReactNode return item.value; }; return ( AutoComplete data{list} style{{ width: 250 }} prefix{IconSearch /} onSearch{search} loading{loading} renderItem{renderItem} renderSelectedItem{renderSelectedItem} onSelect{handleSelect} /AutoComplete ); }实现层面index.tsx 的renderLoading在loading为 true 时渲染一个带.semi-autocomplete-loading-wrapper类名的Spin加载动画覆盖在下拉列表内容之上variables.scss 中为其定义了上下内边距$spacing-autoComplete_loading_wrapper-paddingTop/paddingBottom。远程搜索进阶技巧上述示例在真实网络场景中建议将loading置于请求发出时、data更新与loading关闭置于响应返回时配合setTimeout/clearTimeout或debounce避免高频请求。handleDataChange在 data 变化时会触发rePositionDropdown因此异步返回后浮层宽度与位置会自动校正。尺寸与布局控制尺寸size通过设置size可设置输入框尺寸可选small、default默认、largeimport React from react; import { AutoComplete } from douyinfe/semi-ui; () ( div AutoComplete data{[1, 2, 3, 4]} sizesmall placeholder{small} style{{ width: 200 }} /AutoComplete br / br / AutoComplete data{[1, 2, 3, 4]} sizedefault placeholder{default} style{{ width: 200 }} /AutoComplete br / br / AutoComplete data{[1, 2, 3, 4]} sizelarge placeholder{large} style{{ width: 200 }} /AutoComplete /div );源码中constants.ts 将SIZE限定为[small, large, default]size最终透传给内部的 Input 组件渲染出semi-input-small/semi-input-large等尺寸类名测试用例 autoComplete.test.js 对此有断言。下拉菜单的位置position通过设置position可设置下拉菜单位置可选值与 Tooltip 组件一致bottomLeft为默认值另有top、rightTop等import React from react; import { AutoComplete } from douyinfe/semi-ui; () { const [data, setData] useState([]); const change (input) { let newData [gmail.com, 163.com, qq.com].map(domain ${input}${domain}); if (!input) { newData []; } setData(newData); }; return ( div AutoComplete data{data} positiontop onSearch{change} placeholder选项菜单在上方显示 style{{ width: 200, margin: 10 }} /AutoComplete AutoComplete data{data} positionrightTop onSearch{change} placeholder选项菜单在右侧显示 style{{ width: 200, margin: 10 }} /AutoComplete /div ); };constants.ts 中POSITION直接复用了 tooltip 的POSITION_SET而 index.tsx 渲染时把position、motion、zIndex、getPopupContainer、rePosKey等全部透传给Popover组件——AutoComplete 的下拉浮层本质上是基于 PopoverTooltip 体系实现的因此 Tooltip 支持的位置、动画、遮挡自动调整等能力都可以直接复用。浮层宽度与 dropdownMatchSelectWidthfoundation.ts 的_setDropdownWidth处理下拉宽度当dropdownMatchSelectWidth为 true默认时优先取style.width数字或非百分比字符串否则取触发元素trigger的实测宽度该宽度会作为下拉列表的minWidth生效。因此浮层默认与输入框等宽也可以显式传入dropdownStyle覆盖。状态与交互配置禁用disabledimport React from react; import { AutoComplete } from douyinfe/semi-ui; () ( AutoComplete data{[1, 2, 3, 4]} placeholder{禁用下拉菜单} disabled style{{ width: 200 }}/AutoComplete );disabled会同时禁用输入与下拉交互输入框外层添加semi-autocomplete-disabled类名index.tsx且handleInputClick在disabled时直接返回、不会展开面板foundation.ts。校验状态validateStatus可设置不同校验状态展示不同样式可选default、error、warning仅影响展示样式不阻断交互import React from react; import { AutoComplete } from douyinfe/semi-ui; () ( AutoComplete defaultValueies validateStatuswarning/AutoComplete br / br / AutoComplete defaultValueies validateStatuserror/AutoComplete br / br / AutoComplete defaultValueies/AutoComplete / );validateStatus最终透传给内部 Input 渲染对应边框颜色常与 Form 表单校验联动。自定义空内容emptyContent当data为空时默认下拉列表不显示内容通过emptyContent可自定义空状态展示import React from react; import { AutoComplete, Empty } from douyinfe/semi-ui; import { IllustrationNoContent } from douyinfe/semi-illustrations; () { let [data, setData] useState([]); const [loading, setLoading] useState(false); const fetchData v { setLoading(true); setTimeout(() { if (!v) { setData([]); setLoading(false); return; } setData(() { const res Array.from(Array(5)).map(c Math.random()); return res; }); setLoading(false); }, 1000); }; return ( AutoComplete loading{loading} data{data} emptyContent{Empty style{{ padding: 12, width: 300 }} image{IllustrationNoContent style{{ width: 150, height: 150 }}/} description{暂无内容} /} onSearch{fetchData} / ); };从 index.tsx 可见当options.length 0时下拉内容直接渲染emptyContent因此配合Empty组件 semi-illustrations 插画可以做出非常丰富的空状态。API 参考完整参数表以下为 AutoComplete 全部 API整理自 index.md 并结合 index.tsx 的 Props 定义与 defaultProps 补充默认值属性说明类型默认值版本autoFocus是否自动聚焦boolfalse-autoAdjustOverflow浮层被遮挡时是否自动调整方向booltrue-className样式类名string--clearIcon自定义清除按钮showClear为 true 时有效ReactNode-2.25.0data候选项数据源可为字符串数组或对象数组对象需含label、valuearray[]-defaultActiveFirstOption是否默认高亮第一个选项按回车可直接选中boolfalse-defaultOpen是否默认展开下拉菜单booleanfalse-defaultValue默认值string--disabled是否禁用booleanfalse-dropdownClassName下拉列表的 CSS 类名string--dropdownStyle下拉列表的内联样式object--emptyContentdata 为空时自定义下拉内容ReactNodenull-getPopupContainer指定下拉浮层的父级容器自定义时需给容器设置position: relative会改变浮层 DOM 树位置但不改变视图渲染位置() HTMLElement() document.body-loading下拉列表是否展示加载动画booleanfalse-maxHeight下拉列表的最大高度number | string300-motion下拉列表出现/隐藏时是否有动画booleantrue-onSelectWithObject点击候选项时是否将选中项 option 的其他属性也作为回调入参。为 true 时 onSelect 入参从string变为 object:{ value, label, ...rest }booleanfalse-placeholder输入框默认提示文案string--position下拉菜单显示位置可选值同 Tooltip 组件stringbottomLeft-prefix选择框的前缀标签ReactNode--renderItem控制下拉列表候选项的渲染(option: string | Item) ReactNode--renderSelectedItem候选项被选中后在输入框中的渲染内容仅支持 String 类型返回值(option: string | Item) string--showClear是否展示清除按钮booleanfalse-size尺寸可选small、default、largestringdefault-style样式object--suffix选择框的后缀标签ReactNode--validateStatus校验状态可选default、error、warning仅影响展示样式stringdefault-value当前值string | number无-zIndex下拉菜单的 zIndexnumber--onBlur失去焦点时的回调Function(event)--onChange输入框变化/候选项选中时的变化回调Function(value: string | number)--onFocus获得焦点时的回调Function(event)--onKeyDownkeydown 回调(e: React.KeyboardEvent) void-2.21.0onSearch输入变化时的回调Function(value: string)--onSelect下拉菜单候选项被选中时的回调Function(item: string | number | Item)--几个需要重点理解的参数onSelectWithObjectonSelect 的入参形态默认为 false 时onSelect收到的是字符串值设为 true 后收到的是{ value, label, ...rest }完整对象。其底层实现位于 foundation.ts_backwardLabelInValue()直接读取该属性notifySelect据此决定透传 option 对象还是option.value。测试用例 autoComplete.test.js 与 L1949-L1965 分别验证了两种模式。onChangeWithObject与 onSelectWithObject 配套文档 API 表未单列但在 Props 定义中存在index.tsx用于控制 onChange 是否返回完整对象测试见 autoComplete.test.js。defaultActiveFirstOption设为 true 时面板打开后默认高亮第一个选项用户直接按回车即可选中。源码中 index.tsx 初始focusIndex即props.defaultActiveFirstOption ? 0 : -1foundation.ts 的_modifyFocusIndex也据此在搜索后维持第一项高亮。getPopupContainer默认渲染到document.body。自定义容器时必须给容器设置position: relative否则浮层定位会异常该设置只改变浮层在 DOM 树中的位置不改变视图中的渲染位置。这在处理浮层被父容器 overflow: hidden 裁剪的场景时非常有用。maxHeight下拉列表最大高度默认 300可传数字或字符串如400px在 index.tsx 中作为列表style.maxHeight生效。无障碍Accessibility键盘与焦点AutoComplete 在键盘操作上做了完整的无障碍支持AutoComplete 的 input 框可被聚焦聚焦后键盘用户可以通过上箭头或下箭头打开选项面板如有也支持通过Enter键打开和收起面板若将defaultActiveFirstOption设为 true选项面板打开后默认高亮第一个选项若下拉菜单已打开使用Esc可以关闭菜单使用上箭头或下箭头可以切换选项支持循环切换并且会自动跳过disabled的选项被聚焦的选项可以通过Enter键选中并收起面板。这些行为全部可以在 foundation.ts 的键盘处理链路中找到实现_handleKeyDown按 keyCode 分发UP/DOWN调用_handleArrowKeyDownENTER调用_handleEnterKeyDownESC/TAB直接关闭下拉_getEnableFocusIndex(offset)实现焦点循环与 disabled 选项跳过逻辑并通过updateScrollTop让当前高亮项自动滚动到可视区域中间index.tsx 的 adapter 实现_handleEnterKeyDown在面板关闭时按 Enter 会打开面板面板打开且存在高亮项时按 Enter 会执行handleSelect选中并收起面板键盘事件在handleFocus时通过bindKeyBoardEvent绑定到输入框foundation.ts。此外下拉列表容器带有rolelistboxindex.tsx每个候选项带有roleoption、aria-selected、aria-disabledoption.tsxaria-label、aria-labelledby、aria-invalid、aria-errormessage、aria-describedby、aria-required等 ARIA 属性也支持直接透传index.tsx方便与读屏软件配合。文案规范与设计变量文案规范需要清晰地展示内容让用户显而易见地感知到可用的各个选项限制一次性展示的选项数量——建议配合maxHeight与后端分页/截断策略避免超长列表影响可读性与性能。设计变量Design TokenAutoComplete 的样式全部通过 SCSS 设计变量驱动见 packages/semi-foundation/autoComplete/variables.scss可参与 Semi 的 Design Token 定制体系content/advanced/customize-theme/index.md。常用的变量包括变量作用$color-autoComplete_option_main-text候选项文本颜色默认var(--semi-color-text-0)$color-autoComplete_option-bg-hover候选项悬停背景默认var(--semi-color-fill-0)$color-autoComplete_option-bg-active候选项按下背景默认var(--semi-color-fill-1)$color-autoComplete_option_disabled-text禁用候选项文字颜色$color-autoComplete_option_keyword-text命中的搜索关键词高亮颜色默认var(--semi-color-primary)$font-autoComplete_keyword-fontWeight关键词高亮字重600$spacing-autoComplete_option-paddingTop/paddingBottom候选项上下内边距$spacing-autoComplete_option_first-marginTop第一个候选项顶部外边距$radius-autoComplete_option候选项圆角$width-autoComplete_option_tick选中对勾图标尺寸源码架构从 React 组件到 Foundation 状态机理解 AutoComplete 的内部结构有助于排查问题与二次开发。Semi Design 采用UI 层 Foundation 层的双层架构semi-ui/autoCompleteReact 视图层 ├── index.tsx # AutoComplete 主组件状态渲染、事件桥接、Popover 浮层 └── option.tsx # Option 候选项组件含关键词高亮、禁用、聚焦态 semi-foundation/autoComplete纯逻辑层与框架无关 ├── foundation.ts # AutoCompleteFoundation全部交互状态机 ├── optionFoundation.ts ├── constants.ts # cssClasses / strings 常量 ├── autoComplete.scss / option.scss / animation.scss / rtl.scss └── variables.scss # 设计变量核心调用链以输入 → 展示建议 → 选中为例用户在 Input 中输入onChange触发this.onSearchindex.tsxhandleSearch更新输入值、触发onSearch/onChange回调、必要时打开面板foundation.ts外部更新data后componentDidUpdate检测到变化handleDataChange通过_generateList重新生成 option 列表并重定位浮层foundation.ts用户点击/回车选中候选项handleSelect执行renderSelectedItem校验字符串返回值、更新输入值/选中态、触发onSelect与onChange、关闭面板foundation.ts浮层打开时通过registerClickOutsideHandler监听全局mousedown点击浮层与输入框外部任意区域即关闭index.tsx。Component-DOM 双向同步视图层通过adapter适配器把更新输入值、切换面板可见、更新选项列表、更新焦点索引、通知回调等操作桥接给 FoundationFoundation 不依赖任何 React API因此同一套逻辑可以被 React 与未来的 Web Components 版本复用仓库中的 packages/semi-foundation/README.md 描述了这一架构模式。浮层实现AutoComplete 的下拉面板由 Popover 承载index.tsxtriggercustom且visible由内部状态控制rePosKey每次数据变化自增驱动浮层重新计算位置。这解释了为什么position、autoAdjustOverflow、motion、mouseEnterDelay、mouseLeaveDelay、getPopupContainer、zIndex这些属性与 Tooltip/Popover 完全同源。总结AutoComplete 是 Semi Design 中输入框 建议浮层场景的标准答案它以增强版 Input 的定位区别于 Select通过onSearchdata的开发者自驱数据流实现本地过滤与远程搜索借助renderItem/renderSelectedItem实现高度自定义的选项展示并通过 Foundation 状态机提供了完善的键盘操作与无障碍支持。掌握本文的 API 细节与源码调用链你可以在表单联想、搜索框、邮箱补全等场景中快速落地并依据 packages/semi-foundation/autoComplete/variables.scss 中的设计变量将外观无缝融入自有设计体系。【免费下载链接】semi-designA modern, comprehensive, flexible design system and React UI library, AI-friendly built-in.Provide 3000 Design Tokens, easy to build your design system. Make Semi Design to Any Design. Design to Code in one click项目地址: https://gitcode.com/gh_mirrors/se/semi-design创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考