输入类

自动完成

输入框自动填充。

使用场景

用于对输入框提供输入建议,进行自动补全的操作

与可搜索的 Select 组件的区别:

  • AutoComplete 本质上是一个增强型的提供了输入建议的 Input 组件,而 Select 是一个选择器
  • 点击展开时,Select 会将输入框的值全部清空,而 AutoComplete 会保留上次选中的值
  • Select 的已选项渲染(#selectedItem 插槽)可以是任意节点,而 AutoComplete 的 renderSelectedItem 只允许返回字符串

代码演示

如何引入

<script setup lang="ts">
    import { AutoComplete } from '@fibrous/semi-ui-vue';
</script>

基本用法

通过 @search 监听用户输入,将输入建议通过更新 data 传入。用 v-model 保持受控,当输入框变化/选中输入项时 v-model 会更新

代码
<script setup lang="ts">
    import { ref } from 'vue';
    import { IconSearch } from '@fibrous/semi-icons-vue';
    import { AutoComplete } from '@fibrous/semi-ui-vue';

    const stringData = ref<string[]>([]);
    const value = ref<string | number>('');

    const handleStringSearch = (input: string) => {
        stringData.value = input ? ['gmail.com', '163.com', 'qq.com'].map((domain) => `${input}@${domain}`) : [];
    };

    const handleChange = (input: string | number) => {
        console.log('onChange', input);
    };
</script>

<template>
    <AutoComplete v-model="value" :data="stringData" placeholder="搜索... " showClear style="width: 200px" @change="handleChange" @search="handleStringSearch">
        <template #prefix>
            <IconSearch />
        </template>
    </AutoComplete>
</template>

自定义候选项渲染

需要自定义候选项渲染时,data 可以传入一个对象数组(每个 Object 含有 label、value 两个 key,value 为候选项选中的值,label 为候选项展示的文本,缺省时显示 value)
通过 #item="{ item, index }" 插槽可以自定义候选项的内容:item 是传入的数据项本身,数据项里只放数据,节点写在插槽里

代码
<script setup lang="ts">
    import { ref } from 'vue';
    import { IconSearch } from '@fibrous/semi-icons-vue';
    import { AutoComplete, Avatar } from '@fibrous/semi-ui-vue';

    interface ListItem {
        name: string;
        email: string;
        abbr: string;
        color: 'amber' | 'indigo' | 'blue' | 'cyan';
        value?: string;
        label?: string;
    }

    const list: ListItem[] = [
        { name: '夏可漫', email: 'xiakeman@example.com', abbr: 'XK', color: 'amber' },
        { name: '申悦', email: 'shenyue@example.com', abbr: 'SY', color: 'indigo' },
        { name: '曲晨一', email: 'quchenyi@example.com', abbr: 'CY', color: 'blue' },
        { name: '文嘉茂', email: 'wenjiamao@example.com', abbr: 'JM', color: 'cyan' },
    ];

    const data = ref<ListItem[]>([]);

    const handleStringSearch = (value: string) => {
        data.value = value ? list.map((item) => ({ ...item, value: item.name, label: item.email })) : [];
    };

    const renderSelectedItem = (option: ListItem) => option.email;
</script>

<template>
    <AutoComplete aria-label="搜索邮箱" :data="data" :renderSelectedItem="renderSelectedItem" showClear style="width: 280px" @search="handleStringSearch">
        <template #prefix>
            <IconSearch />
        </template>
        <template #item="{ item }">
            <Avatar :color="item.color" size="small">{{ item.abbr }}</Avatar>
            <div style="margin-left: 4px">
                <div style="font-size: 14px; margin-left: 4px">{{ item.name }}</div>
                <div style="margin-left: 4px">{{ item.email }}</div>
            </div>
        </template>
    </AutoComplete>
</template>

远程搜索

从 @search 中获取用户输入值,动态更新 data 值

尺寸

通过设置 size 可设置输入框尺寸,可选small,default(默认),large





代码
<script setup lang="ts">
    import { AutoComplete } from '@fibrous/semi-ui-vue';

    const data = [1, 2, 3, 4];
</script>

<template>
    <div>
        <AutoComplete :data="data" placeholder="small" size="small" style="width: 200px" />
        <br />
        <br />
        <AutoComplete :data="data" placeholder="default" size="default" style="width: 200px" />
        <br />
        <br />
        <AutoComplete :data="data" placeholder="large" size="large" style="width: 200px" />
    </div>
</template>

下拉菜单的位置

通过设置 position 可设置下拉菜单位置,可选值参考 Tooltip position

代码
<script setup lang="ts">
    import { ref } from 'vue';
    import { AutoComplete } from '@fibrous/semi-ui-vue';

    const data = ref<string[]>([]);

    const change = (input: string) => {
        data.value = input ? ['gmail.com', '163.com', 'qq.com'].map((domain) => `${input}@${domain}`) : [];
    };
</script>

<template>
    <div>
        <AutoComplete :data="data" placeholder="选项菜单在上方显示" position="top" style="width: 200px; margin: 10px" @search="change" />
        <AutoComplete :data="data" placeholder="选项菜单在右侧显示" position="rightTop" style="width: 200px; margin: 10px" @search="change" />
    </div>
</template>

禁用

代码
<script setup lang="ts">
    import { AutoComplete } from '@fibrous/semi-ui-vue';

    const data = [1, 2, 3, 4];
</script>

<template>
    <AutoComplete :data="data" disabled placeholder="禁用下拉菜单" style="width: 200px" />
</template>

校验状态

可设置不同校验状态,展示不同样式





代码
<script setup lang="ts">
    import { AutoComplete } from '@fibrous/semi-ui-vue';
</script>

<template>
    <AutoComplete aria-label="Warning status" defaultValue="ies" validateStatus="warning" />
    <br />
    <br />
    <AutoComplete aria-label="Error status" defaultValue="ies" validateStatus="error" />
    <br />
    <br />
    <AutoComplete aria-label="Default status" defaultValue="ies" />
</template>

自定义空内容

可设置自定义展示空内容

代码
<script setup lang="ts">
    import { ref } from 'vue';
    import { IllustrationNoContent } from '@fibrous/semi-illustrations-vue';
    import { AutoComplete, Empty } from '@fibrous/semi-ui-vue';

    const data = ref<number[]>([]);
    const loading = ref(false);

    const fetchData = (input: string) => {
        loading.value = true;
        setTimeout(() => {
            data.value = input ? Array.from({ length: 5 }, () => Math.random()) : [];
            loading.value = false;
        }, 1000);
    };
</script>

<template>
    <AutoComplete aria-label="搜索" :data="data" :loading="loading" @search="fetchData">
        <template #emptyContent>
            <Empty style="padding: 12px; width: 300px">
                <template #image>
                    <IllustrationNoContent style="width: 150px; height: 150px" />
                </template>
                <template #description>暂无内容</template>
            </Empty>
        </template>
    </AutoComplete>
</template>

API 参考

Props

属性说明类型默认值
modelValue输入框的当前值,用 v-model 绑定。传入后为受控;传入 undefined 时按非受控处理。string | numberundefined
modelModifiersv-model 修饰符 trim 与 number,由 Vue 在使用 v-model.trim、v-model.number 时传入。ModelModifiersundefined
defaultValue非受控时输入框的初始值。string | numbersemiGlobalDefault("AutoComplete", "defaultValue")
data候选项的数据源,可以是字符串、数字或对象的数组。对象项用 value 作选中值,label 作展示文本(缺省显示 value),disabled、class、style 与 data-* 字段落在对应的候选行上;节点内容用 item 插槽。数组原地修改也会更新列表。T[]semiDefault("AutoComplete", "data", []) as T[]
autofocus是否在挂载后自动聚焦输入框。booleansemiDefault("AutoComplete", "autofocus", false)
autoAdjustOverflow下拉面板被遮挡时是否自动调整方向。booleansemiGlobalDefault("AutoComplete", "autoAdjustOverflow")
defaultActiveFirstOption面板打开后是否默认高亮第一个候选项,此时按 Enter 可直接选中。booleansemiDefault("AutoComplete", "defaultActiveFirstOption", false)
defaultOpen挂载时是否默认展开下拉面板。booleansemiGlobalDefault("AutoComplete", "defaultOpen")
disabled是否禁用。booleansemiGlobalDefault("AutoComplete", "disabled")
dropdownClassName下拉列表的类名,落在 role="listbox" 元素上。stringsemiGlobalDefault("AutoComplete", "dropdownClassName")
dropdownMatchSelectWidth下拉面板的最小宽度是否等于输入框宽度。booleansemiDefault("AutoComplete", "dropdownMatchSelectWidth", true)
dropdownStyle下拉列表的内联样式,落在 role="listbox" 元素上。StyleValuesemiGlobalDefault("AutoComplete", "dropdownStyle")
insetLabelIdinsetLabel 前缀元素的 id,combobox 与 listbox 的名称引用它;不传时组件在渲染 insetLabel 时生成。stringundefined
loading下拉列表是否显示加载动画;为 true 时代替候选项和空内容。booleansemiDefault("AutoComplete", "loading", false)
maxHeight下拉列表的最大高度,数字按 px 处理。string | numbersemiDefault("AutoComplete", "maxHeight", 300)
motion下拉面板显示、隐藏时是否有动画。booleansemiDefault("AutoComplete", "motion", true)
selectWithObject布尔属性,不是事件:为 true 时,select 事件收到去掉内部字段的数据项对象,而不是选中值。booleansemiDefault("AutoComplete", "selectWithObject", false)
placeholder输入框的提示文案。stringsemiGlobalDefault("AutoComplete", "placeholder")
position下拉面板的位置,可选值同 Tooltip 的 position。未设置时为 bottomLeft,ConfigProvider 的 direction 为 rtl 时为 bottomRight。Type"top" | "bottom" | "left" | "right" | "topLeft" | "topRight" | "leftTop" | "leftBottom" | "rightTop" | "rightBottom" | "bottomLeft" | "bottomRight" | "leftTopOver" | "rightTopOver" | "leftBottomOver" | "rightBottomOver"semiGlobalDefault("AutoComplete", "position")
renderSelectedItem选中候选项后输入框显示的文本,必须返回字符串;字符串或数字项收到 { value, label },对象项收到数据项本身。保留为函数 prop,因为 foundation 在渲染之外调用它。Type((option: AutoCompleteSelectedItem<T>) => string)undefined
showClear有内容时是否显示清除按钮。booleansemiDefault("AutoComplete", "showClear", false)
size输入框尺寸。SizesemiDefault("AutoComplete", "size", "default")
stopPropagation是否阻止下拉面板上的 click、mousedown 与焦点进出事件冒泡。string | booleansemiDefault("AutoComplete", "stopPropagation", true)
validateStatus校验状态,只影响展示样式。"default" | "error" | "warning" | "success"semiDefault("AutoComplete", "validateStatus", "default")

Events

事件说明回调参数
update:modelValue输入框内容变化或选中候选项时触发,供 v-model 回写;先于 change 触发。[value: string | number]
change输入框内容变化或选中候选项时触发。它是组件事件,会遮住输入框原生的 change 事件。[value: string | number]
search用户输入时触发,参数为输入的文本。[inputValue: string]
select选中候选项时触发,参数为选中值;设置 selectWithObject 时为去掉内部字段的数据项。[value: string | number | AutoCompleteDataItem]
clear用清除按钮清空内容后触发。[]
focus焦点进入组件时触发一次。它是组件事件,会遮住原生的 focus 事件。[event: FocusEvent]
blur焦点离开组件时触发一次。它是组件事件,会遮住原生的 blur 事件。[event: FocusEvent]
dropdownVisibleChange下拉面板显示或隐藏时触发,参数为是否可见;放在 KeepAlive 中失活时也会以 false 触发。[visible: boolean]
keydown组件处理完按键之后触发,参数为 KeyboardEvent。它会遮住原生的 keydown 事件。[event: KeyboardEvent]

Slots

插槽说明作用域参数
prefix输入框的前缀内容。any
suffix输入框的后缀内容。any
insetLabel输入框内嵌标签。设置 prefix 或 trigger 时不渲染,也不作为可访问名称。any
clearIcon自定义清除图标,showClear 为 true 时有效。any
emptyContentdata 为空时在下拉面板中显示的内容。any
item候选项行内的内容,参数 item 是未经加工的数据项,index 是它在已渲染候选项中的位置;不提供时显示 label。TypeAutoCompleteItemSlotProps<T>
trigger替换输入框。参数含 value、inputValue、placeholder、disabled、autofocus、size、validateStatus、showClear、insetLabelId、onChange(更新输入文本,触发 search 与 change 并展开列表)、onClear、onFocus、onBlur、controlAttrs(传给组件的 aria-* 属性,放到自定义触发器的可聚焦元素上)与 componentProps。使用时 id 落在根元素上。TypeAutoCompleteTriggerSlotProps<T>

Exposes

名称说明类型
无

id、name 以及 aria-describedby、aria-errormessage、aria-invalid、aria-label、aria-labelledby、aria-required 落在输入框(role="combobox")上,<label for> 因此能关联到输入框;class、style、data-* 和其他未声明的属性与监听器(例如 @click)落在根 div 上,根 div 的 tabindex 固定为 -1。使用 #trigger 时没有输入框,id 落在根 div 上,name 不落到任何元素,aria-* 通过插槽参数 controlAttrs 交给自定义触发器的可聚焦元素。

data 的对象项:

字段说明类型
value选中后的值string | number
label候选项展示的文本,缺省时显示 value;节点内容用 #item 插槽string | number
disabled是否禁用该候选项boolean
class候选行的类名string | object | array
style候选行的样式StyleValue

其他字段原样保留,出现在 #item 插槽的 item 和 @select 的载荷里(设置 selectWithObject 时)。以 data- 开头的字段落在候选行上。字符串和数字项在 renderSelectedItem 中以 { value, label } 形式收到。

AutoComplete 通过模板 ref 暴露下列成员,类型为 AutoCompleteHandle:

成员说明类型
nativeElement只读,包裹输入框或自定义触发器的根 div,未挂载时为 nullHTMLDivElement | null

Accessibility

键盘和焦点

  • AutoComplete 的 input 框带有 role="combobox",并通过 aria-expanded、aria-controls、aria-autocomplete="list" 和 aria-activedescendant 与选项面板关联
  • combobox 的名称按优先级取:aria-labelledby、aria-label、实际渲染出来的 insetLabel(combobox 的 aria-labelledby 指向它,未传 insetLabelId 时组件生成 id;有 prefix 时 insetLabel 不渲染,也不作名称)。listbox 使用同一个名称来源。AutoComplete 没有默认名称:以上都没有时,请用 aria-label 或 aria-labelledby 为输入框命名;<label for> 只命名输入框,listbox 仍没有名称
  • AutoComplete 的 input 框可被聚焦,聚焦后,键盘用户可以通过 上箭头 或 下箭头 打开选项面板;data 为空时面板里显示 emptyContent(没有提供时为空),加载中显示加载动画
  • AutoComplete 也支持通过 Enter 键打开和收起面板
  • 若用户将 defaultActiveFirstOption 属性设置为 true 时,选项面板打开后默认高亮第一个选项
  • 若下拉菜单打开时:
    • 使用 Esc 可以关闭菜单
    • 使用 Tab 可以关闭菜单,焦点照常移到下一个可聚焦元素
    • 使用 上箭头 或 下箭头 可以切换选项,被高亮的选项(aria-activedescendant 指向的项)aria-selected 为 true
    • 被聚焦的选项可以通过 Enter 键选中,并收起面板
    • 用鼠标选中选项后,焦点留在输入框中
  • showClear 开启且有内容时,清除按钮与 Input 相同:原生 button,名称为语言包中的「清空输入」,从输入框按 Tab 移到它,Enter 或空格键清空并把焦点放回输入框

文案规范

  • 需要清晰地展示内容,让用户显而易见地感知到可用的各个选项
  • 限制一次性展示的选项数量

设计变量

下表是组件内部的 Sass 变量,不能覆写。定制样式请覆写 --semi-* CSS 变量(见 Design Token 页),或写不分层的 CSS 规则。
Sass 变量值用法
$transition_duration-autoComplete_option-bgvar(--semi-transition_duration-none)选择器-选项-动画持续时间
$transition_function-autoComplete_option-bgvar(--semi-transition_function-easeIn)选择器-选项-过渡曲线
$transition_delay-autoComplete_option-bgvar(--semi-transition_delay-none)选择器-选项-延迟时间
$spacing-autoComplete_loading_wrapper-paddingTop$spacing-tight加载搜索结果时的顶部内边距
$spacing-autoComplete_loading_wrapper-paddingBottom$spacing-tight加载搜索结果时的底部内边距
$color-autoComplete_option-icon-defaulttransparent自动完成菜单选项图标颜色 - 默认态
$color-autoComplete_option-bg-hovervar(--semi-color-fill-0)自动完成菜单选项背景颜色 - 悬停态
$color-autoComplete_option-bg-activevar(--semi-color-fill-1)自动完成菜单选项背景颜色 - 按下态
$color-autoComplete_option_disabled-textvar(--semi-color-disabled-text)禁用自动完成菜单选项文字颜色
$width-autoComplete_option_tick$width-icon-small自动完成菜单项选中对勾图标大小
$spacing-autoComplete_option_tick-marginRight$spacing-tight自动完成菜单选中对勾右侧外边距
$spacing-autoComplete_option-paddingLeft$spacing-base-tight自动完成菜单项左侧内边距
$spacing-autoComplete_option-paddingRight$spacing-base-tight自动完成菜单项右侧内边距
$spacing-autoComplete_option-paddingTop$spacing-tight自动完成菜单项顶部内边距
$spacing-autoComplete_option-paddingBottom$spacing-tight自动完成菜单项底部内边距
$spacing-autoComplete_option_first-marginTop$spacing-extra-tight自动完成第一个菜单项顶部外边距
$spacing-autoComplete_option_last-marginBottom$spacing-extra-tight自动完成最后一个菜单项顶部外边距
$radius-autoComplete_option0px自动完成待选项圆角
$color-autoComplete_option_main-textvar(--semi-color-text-0)自动完成菜单选项文本颜色