vue-devui AutoComplete 自动补全组件实战:数据源配置、自定义匹配、懒加载与源码实现解析
前端UI组件设计系统【免费下载链接】vue-devui基于全新 DevUI Design 设计体系的 Vue3 组件库面向研发工具的开源前端解决方案。项目地址https://gitcode.com/DevCloudFE/vue-devui点击查看免费下载在研发工具类产品中输入框往往不只是打字的地方用户需要根据已输入的部分字符快速推断出完整的候选项如语言名、命令、标签、仓库名。vue-devui 的d-auto-completeAutoComplete 自动补全组件正是为此设计它内置防抖搜索、键盘导航、下拉弹层定位、最近输入展示与滚动懒加载等能力。本文基于官方组件文档 auto-complete/index.md 展开并结合 组件源码 与 测试用例带你完整掌握 AutoComplete 的每一项配置、事件与插槽并理解其底层实现机制。何时使用当需要根据用户输入的部分字符推断出他可能想要输入的内容时使用 AutoComplete。典型场景包括搜索框联想输入前缀自动补全研发工具中的命令/语言/标签名快速选择配合最近输入能力降低重复操作成本。组件的导出入口在 packages/devui-vue/devui/auto-complete/index.ts它被归类为数据录入类组件通过install方法以DAutoComplete名称注册// packages/devui-vue/devui/auto-complete/index.ts export default { title: AutoComplete 自动补全, category: 数据录入, status: 100%, install(app: App): void { app.component(AutoComplete.name, AutoComplete); }, };基本用法通过source设置自动完成的数据源。数据源支持string[]或{ label, disabled }对象数组两种形式类型定义见 auto-complete-types.ts。template d-auto-complete :delay1000 :sourcesource v-modelvalue :allow-empty-value-searchallowEmptyValueSearch :select-valueselectValue :trans-input-focus-emittransInputFocusEmit :positionposition :width420 :append-to-bodyfalse /d-auto-complete /template script import { defineComponent, ref } from vue; export default defineComponent({ setup() { const value ref(); const allowEmptyValueSearch ref(true); const source ref([ C#, C, C, CPython, Java, JavaScript, Go, Python, Ruby, F#, TypeScript, SQL, LiveScript, CoffeeScript, ]); const selectValue (e) { console.log(selectValue, e); }; const transInputFocusEmit () { console.log(transInputFocusEmit); }; const position ref([bottom]); return { value, source, allowEmptyValueSearch, transInputFocusEmit, selectValue, position, }; }, }); /script几个关键行为的源码依据防抖搜索输入事件并非立即触发搜索。在 use-input-handle.ts 中onInput先发出update:modelValue更新绑定值随后通过debounce(onInputCb, delay.value)以delay默认 300ms为等待时间防抖执行handleSearch。每次输入都会清空上一次的定时器即只有 delay 时间经过后且未输入新值才做搜索查询。防抖执行期间searchStatus被置为true用于配合searching插槽展示搜索中状态。空值搜索allowEmptyValueSearch为false时输入内容为空直接清空searchList且不显示无匹配提示为true时聚焦空输入框也会执行全量匹配见 use-searchfn.ts 中handleSearch对空 term 的分支处理。弹层定位下拉弹层由FlexibleOverlay渲染position接收一个位置候选数组弹层按顺序尝试落位append-to-body为true时通过Teleport tobody将弹层传送到 body避免被父容器overflow: hidden裁剪见 auto-complete.tsx 的renderDropdown。需要说明的是文档中position默认值标注为[bottom]而从源码 props 定义看未传position时实际默认为[bottom, top, left, right]由 overlay 自动择位。失焦/点击外部关闭组件根节点绑定了click-outside指令触发handleClose将弹层隐藏并重置搜索状态。尺寸支持sm、md、lg三种尺寸默认为md。尺寸最终体现为根节点的d-auto-complete--sm / d-auto-complete--lg修饰类md不加修饰类。template h4Small/h4 d-auto-complete sizesm :sourcesource v-modelvalue1 :width420 /d-auto-complete h4Middle/h4 d-auto-complete :sourcesource v-modelvalue2 :width420 /d-auto-complete h4Large/h4 d-auto-complete sizelg :sourcesource v-modelvalue3 :width420 /d-auto-complete /template script import { defineComponent, ref } from vue; export default defineComponent({ setup() { const value1 ref(); const value2 ref(); const value3 ref(); const source ref([C#, C, C]); return { value1, value2, value3, source }; }, }); /script值得一提的是AutoComplete 会响应d-form上下文从源码看autoCompleteSize计算属性优先取formContext?.size未传size时会继承表单级别的尺寸isDisabled同样优先取formContext?.disabled见 auto-complete.tsx 中inject(FORM_TOKEN)相关逻辑。设置禁用通过disabled设置是否禁用。禁用后输入框disabled属性生效且点击输入框不会展开下拉菜单toggleMenu中会先判断isDisabled。template d-row typeflex d-col :flex4 d-auto-complete :sourcesource v-modelvalue :disabledisDisabled /d-auto-complete /d-col d-col :flex2 d-button idprimaryBtn clicktoggle stylemargin-left:10px {{ isDisabled ? 点击启用 : 点击禁用 }} /d-button /d-col /d-row /template script import { defineComponent, ref } from vue; export default defineComponent({ setup() { const value ref(); const source ref([ C#, C, C, CPython, Java, JavaScript, Go, Python, Ruby, F#, TypeScript, SQL, LiveScript, CoffeeScript, ]); const isDisabled ref(false); function toggle() { isDisabled.value !isDisabled.value; } return { value, source, isDisabled, toggle }; }, }); /script对应地clearable的清空图标只在clearable !isDisabled时渲染见源码showClearable计算属性测试用例 auto-complete.spec.ts 中的 disabled 用例验证了切换disabled后input.disabled为true。自定义数据匹配方法当数据源是对象数组、或匹配规则不是简单的前缀匹配时可以通过search-fn自定义数据的匹配方法和返回的数据格式配合formatter决定每一项的展示文本配合disabled-key指定对象中禁用字段名。template d-auto-complete v-modelvalue :search-fnsearchFn disabled-keydisabled is-searching :delay1000 :formatterformatter template #searchingslotProps div {{ searching: ${slotProps} }} /div /template /d-auto-complete /template script import { defineComponent, ref } from vue; export default defineComponent({ setup() { const value ref(); const mySource ref([ { label: C#, disabled: false }, { label: C, disabled: false }, { label: CPython, disabled: false }, { label: Java, disabled: false }, { label: JavaScript, disabled: false }, { label: Go, disabled: false }, { label: Ruby, disabled: false }, { label: F#, disabled: false }, { label: TypeScript, disabled: false }, { label: SQL, disabled: true }, { label: LiveScript, disabled: false }, { label: CoffeeScript, disabled: false }, ]); const formatter (item) { return item.label; }; // treminput输入内容 const searchFn async (trem) { let arr []; await new Promise((resolve) { setTimeout(() { resolve(); }, 1000); }); mySource.value.forEach((item) { let cur item.label; cur cur.toLowerCase(); if (cur.startsWith(trem)) { arr.push(item); } }); return arr; }; return { value, searchFn, formatter }; }, }); /script源码层面的匹配流程use-searchfn.tshandleSearch(term, enableLazyLoad)先把term转为小写若开启了懒加载enableLazyLoadtrue直接取source全量数据展示懒加载场景下不做前端过滤否则若未提供searchFn走内置defaultSearchFn对每个元素先经formatter取展示文本再toLowerCase().startsWith(term)做前缀匹配若提供了searchFn可以是异步函数await其返回结果。也就是说默认的匹配策略是展示文本小写后以输入串开头而非子串包含如果你需要模糊/包含匹配或对接后端接口就必须自己实现search-fn。is-searching为true且提供了searching插槽时防抖等待期间searchStatus为true下拉区会渲染该插槽参数为当前输入内容——上面 demo 中等待 1 秒的搜索过程就会展示searching: xxx。测试用例 Customized data matching method 验证了输入c后searching模板出现且内容为c输入s后SQL项因disabled: true与disabled-keydisabled的组合而呈现.disabled样式且不可选。自定义模板展示通过item、nothing插槽自定义下拉选项与无匹配项提示。template d-auto-complete :sourcesource v-modelvalue template #itemslotProps div第{{ slotProps.index }}项: {{ slotProps.item }}/div /template template #nothingslotProps div {{ 没有匹配项: ${slotProps} }} /div /template /d-auto-complete /template script import { defineComponent, ref } from vue; export default defineComponent({ setup() { const value ref(); const source ref([ C#, C, C, CPython, Java, JavaScript, Go, Python, Ruby, F#, TypeScript, SQL, LiveScript, CoffeeScript, ]); return { value, source }; }, }); /script从 use-custom-template.ts 可以看到插槽参数的传递细节#item收到的是{ item, index }对象item为当前数据项string或SourceItemObjindex为下标#nothing与#searching收到的都是当前输入值modelValue这三个插槽在根组件中被包装成内部模板后通过provide/injectDropdownPropsKey传递给下拉子组件 dropdown.tsx 渲染。最近输入通过latest-source设置最近输入。当输入框聚焦且当前值为空时下拉区顶部会显示tips-text默认文案最近输入提示并将列表内容替换为latest-sourcetemplate d-auto-complete :sourcesource v-modelvalue :latest-sourcelatestSource /d-auto-complete /template script import { defineComponent, ref } from vue; export default defineComponent({ setup() { const value ref(); const latestSource ref([JavaScript, TypeScript]); const source ref([ C#, C, C, CPython, Java, JavaScript, Go, Python, Ruby, F# , TypeScript, SQL, LiveScript, CoffeeScript, ]); return { value, source, latestSource }; }, }); /script实现上onFocus中会依次调用handleSearch(modelValue)与recentlyFocus(latestSource.value)后者直接把searchList覆写为最近输入列表use-searchfn.ts 中的recentlyFocusdropdown.tsx 中则通过latestSource !modelValue条件渲染提示文案行文案经 i18n 的latestInput键处理实际提示文字由tips-textprop 控制。一旦开始输入就会回到正常的搜索匹配流程。启用懒加载enable-lazy-load开启懒加载适合候选数据量很大、需要滚动分页加载的场景。使用要点必须配合load-more回调下拉列表滚动到底部时触发新数据追加到source后调用组件实例方法loadFinish()关闭 loading 状态并刷新列表value-parser可对选中后的数据做二次加工如对象转字符串scene-type可选select/suggest。template d-auto-complete refautoCompleteRef :sourcesource v-modelvalue enable-lazy-load :load-moreloadMore scene-typeselect :value-parservalueParser /d-auto-complete /template script import { defineComponent, ref } from vue; export default defineComponent({ setup() { const value ref(); const source ref([ C#, C, C, CPython, Java, JavaScript, Go, Python, Ruby, F#, TypeScript, SQL, LiveScript, CoffeeScript, C1, C2, C3, C4, C5, C6, C7, ]); const autoCompleteRef ref(null); const loadMore () { setTimeout(() { source.value.push(lazyData source.value.length); autoCompleteRef.value?.loadFinish(); }, 3000); }; const valueParser (e) { return e 123; }; return { value, source, loadMore, valueParser, autoCompleteRef }; }, }); /script源码中 use-lazy-handle.ts 的滚动判定逻辑为clientHeight scrollTop scrollHeight clientHeight scrollTop maxHeight时调用props.loadMore()并置showLoading下拉区套v-loading指令显示加载动画loadFinish方法通过ctx.expose暴露到组件实例上内部会执行一次handleSearch(modelValue, enableLazyLoad)再关闭 loading。懒加载模式下搜索不再做前端过滤handleSearch中enableLazyLoadtrue分支直接取全量source过滤交由你的分页/后端逻辑完成。AutoComplete 参数参数名类型默认值说明sizeAutoCompleteSizemd输入框尺寸三种选择lg、md、smplaceholderstringSearch占位符sourceSourceType—必选有search-fn的情况下可以不必选allow-empty-value-searchbooleanfalse输入框 value 为空时是否进行搜索提示操作append-to-bodybooleanfalse下拉弹出是否 append to bodypositionPlacement[][bottom]文档口径源码默认[bottom,top,left,right]自动择位指定下拉框与输入框的相对位置disabledbooleanfalse是否禁用delaynumber300只有 delay 时间经过后并且未输入新值才做搜索查询msdisabled-keystring—禁用单个选项时对象中禁用标志的字段名formatter(item: any) stringdefaultFormatter格式化函数决定每项展示文本is-searchingbooleanfalse是否在搜索中用于控制 searching 插槽是否显示scene-typestring—值为select、suggestsearch-fn(term: string) ArrayanydefaultSearchFn自定义搜索过滤可为异步函数tips-textstring最近输入最近输入提示文字latest-sourceArrayany—最近输入数据value-parser(item: any) anydefaultValueParse对选中后数据进行处理enable-lazy-loadbooleanfalse是否允许懒加载widthnumber400调整宽度pxshow-animationbooleantrue是否开启动画弹层 fade 过渡prefixstring—自定义前缀图标suffixstring—自定义后缀图标clearablebooleanfalse是否可清空见 d-input 一键清空show-glow-stylebooleantrue是否显示悬浮发光效果另外从 auto-complete-types.ts 的 props 定义中还可以看到一个未在文档表格中列出的maxHeight默认300单位 px它限制下拉列表ul的最大高度也是懒加载滚动判定的参考值。AutoComplete 事件事件类型说明load-morefunction懒加载触发事件配合enable-lazy-load使用使用$event.loadFinish()关闭 loading 状态其中$event为 AutoCompleteComponent 的实例select-valuefunction(value)选择选项之后的回调函数经formatter处理后的文本trans-input-focus-emitfunctionInput focus 时回调函数此外组件通过emits声明了update:modelValue、clear、blur三个标准事件见 auto-complete.tsx可配合v-model、clear、blur使用作为输入框input、keyup等原生事件也可正常触发测试用例 bindEvents work 有验证。选中回调select-value的触发时机在 use-select-handle.ts点击某一项后依次执行emit(update:modelValue, formatter(item))→handleClose()关闭弹层 →handleSearch刷新列表 → 回调selectValue。AutoComplete 插槽插槽名说明item自定义选项展示模板。slotProps{ index: 下标索引, item: 当前项内容 }nothing没有匹配项时的展示结果。slotProps输入内容searching自定义搜索中显示模板。slotProps输入内容prefix输入框头部内容图标等suffix输入框尾部内容prepend输入框前置内容append输入框后置内容prefix/suffix除 prop 图标名经Icon组件渲染外也支持具名插槽prepend/append插槽分别渲染在输入框外层的前、后位置。测试用例 prefix/suffix/prepend/append slot work 验证了四种插槽均可正常渲染。类型定义以下类型与默认函数在 auto-complete-types.ts 中对外导出export * from ./src/auto-complete-types可在业务代码中直接import使用。SourceTypeinterface SourceItemObj { label: string; disabled: boolean; [propName: string]: unknown; } type SourceType Arraystring | ArraySourceItemObj;Placementtype Placement | top | right | bottom | left | top-start | top-end | right-start | right-end | bottom-start | bottom-end | left-start | left-end;defaultSearchFndefaultSearchFn (term: string) { type ItemType typeof source.value[0]; const arr: ItemType[] []; source.value.forEach((item) { let cur formatter.value(item as ItemType); cur cur.toLowerCase(); if (cur.startsWith(term)) { arr.push(item); } }); return arr as SourceType; };term为输入的关键字。默认匹配是展示文本小写后的前缀匹配与自定义search-fn的行为对比可见若你的search-fn用includes实现匹配效果会明显宽于默认行为。defaultFormatterdefaultFormatter (item: string | SourceItemObj) { if (typeof item string) { return item; } return item ! null ? item.label || item.toString() : ; };item为数据项。字符串原样返回对象取label字段。defaultValueParsedefaultValueParse (item) item;默认原样返回选中项不做加工。AutoCompleteSizetype AutoCompleteSize sm | md | lg;键盘交互与选中高亮AutoComplete 内置完整的键盘操作实现在 use-keyboard-select.tsArrowDown / ArrowUp在候选项间循环移动高亮hoverIndex到末项再按 Down 回到首项反之亦然每次移动都会scrollIntoView保证高亮项可见Enter选中当前高亮项走与点击相同的selectOptionClick流程Escape弹层展开且有候选/搜索中/无匹配模板时关闭弹层。高亮项hoverIndex与已选中项selectedIndex即selected类是两个独立状态下拉渲染时[ns.e(dropdown-bg)]: hoverIndex index控制悬停背景selected类标记当前值对应的项。auto-complete.spec.ts 的 init render KeyboardEvent 用例完整走了一遍该链路输入c后连续 ArrowDown/ArrowUp 移动高亮最终 Enter 后value变为CEscape 后弹层关闭。与 Form 的联动从 use-auto-complete-render.ts 的源码结构看AutoComplete 深度接入了d-form/d-form-item体系inject(FORM_TOKEN)继承表单级disabled与sizeinject(FORM_ITEM_TOKEN)当validateState error时输入框 wrapper 追加错误样式类modelValue变化时自动触发formItemContext.validate(change)即 AutoComplete 作为受控控件参与表单校验校验反馈showFeedback时追加has-feedback相关类名。因此在d-form-item中放置d-auto-complete可以直接获得校验态样式与值变更自动校验能力无需额外配置。小结vue-devui 的d-auto-complete以输入 → 防抖 → 匹配 → 弹层展示 → 键盘/鼠标选择 → 回写 modelValue为核心链路覆盖了自动补全的常见需求静态数据前缀联想source 默认匹配即可远程/对象数据search-fn可异步formatterdisabled-key视觉定制item/nothing/searching插槽与prefix/suffix/prepend/append插槽大列表enable-lazy-loadload-more 实例方法loadFinish()体验细节delay防抖、position/append-to-body弹层控制、latest-source最近输入、clearable一键清空、show-glow-style发光效果。所有行为均可在当前仓库中对照验证主组件 auto-complete.tsx、各组合式函数composables/目录、下拉渲染 dropdown.tsx 以及测试 auto-complete.spec.ts配合官方文档 auto-complete/index.md 中的示例可快速定位每一个配置项的具体作用与默认值。赞分享前端UI组件设计系统【免费下载链接】vue-devui基于全新 DevUI Design 设计体系的 Vue3 组件库面向研发工具的开源前端解决方案。项目地址https://gitcode.com/DevCloudFE/vue-devui点击查看免费下载相关推荐Arco Design AutoComplete 自动补全组件深度指南API 解析、数据源与自定义输入实战Arco Design AutoComplete 自动补全组件深度指南API 解析、数据源与自定义输入实战 自动补全AutoComplete是 ArcoUI组件前端设计系统rsuite AutoComplete 实战用动态数据源实现邮箱域名自动补全rsuite AutoComplete 实战用动态数据源实现邮箱域名自动补全 导读 本文以 rsuite 官方文档中的邮箱自动补全示例 docs/pages前端UI组件Ant Design Blazor AutoComplete 组件实战指南自动补全输入框的配置、查询模式与源码原理Ant Design Blazor AutoComplete 组件实战指南自动补全输入框的配置、查询模式与源码原理 AutoComplete自动完成是 A前端UI组件设计系统创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考