使用场景
用于对输入框提供输入建议,进行自动补全的操作
与可搜索的 Select 组件的区别:
- AutoComplete 本质上是一个增强型的提供了输入建议的 Input 组件,而 Select 是一个选择器
- 点击展开时,Select 会将输入框的值全部清空,而 AutoComplete 会保留上次选中的值
- Select 的已选项渲染(renderSelectedItem)可定制化程度更高,可以为任意类型的 ReactNode,而 AutoComplete 只允许为字符串
代码演示
如何引入
import { AutoComplete } from '@douyinfe/semi-ui';
基本用法
通过 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 }}
/>
);
};
自定义候选项渲染
需要自定义候选项渲染时,data 可以传入一个对象数组(每个 Object 必须含有 label、value 两个 key,value 为候选项选中的值,label 为候选项展示的内容)
通过 renderItem 可以自定义候选项的渲染
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: '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 [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} size="small">
{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 }}
/>
);
};
远程搜索
从 onSearch 中获取用户输入值,动态更新 data 值
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>
);
}
尺寸
通过设置 size 可设置输入框尺寸,可选small
,default
(默认),large
import React from 'react';
import { AutoComplete } from '@douyinfe/semi-ui';
() => (
<div>
<AutoComplete
data={[1, 2, 3, 4]}
size="small"
placeholder={'small'}
style={{ width: 200 }}
></AutoComplete>
<br />
<br />
<AutoComplete
data={[1, 2, 3, 4]}
size="default"
placeholder={'default'}
style={{ width: 200 }}
></AutoComplete>
<br />
<br />
<AutoComplete
data={[1, 2, 3, 4]}
size="large"
placeholder={'large'}
style={{ width: 200 }}
></AutoComplete>
</div>
);
下拉菜单的位置
通过设置 position 可设置下拉菜单位置,可选值参考 Tooltip position
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}
position="top"
onSearch={change}
placeholder="选项菜单在上方显示"
style={{ width: 200, margin: 10 }}
></AutoComplete>
<AutoComplete
data={data}
position="rightTop"
onSearch={change}
placeholder="选项菜单在右侧显示"
style={{ width: 200, margin: 10 }}
></AutoComplete>
</div>
);
};
禁用
import React from 'react';
import { AutoComplete } from '@douyinfe/semi-ui';
() => (
<AutoComplete data={[1, 2, 3, 4]} placeholder={'禁用下拉菜单'} disabled style={{ width: 200 }}></AutoComplete>
);
校验状态
可设置不同校验状态,展示不同样式
import React from 'react';
import { AutoComplete } from '@douyinfe/semi-ui';
() => (
<>
<AutoComplete defaultValue="ies" validateStatus="warning"></AutoComplete>
<br />
<br />
<AutoComplete defaultValue="ies" validateStatus="error"></AutoComplete>
<br />
<br />
<AutoComplete defaultValue="ies"></AutoComplete>
</>
);
自定义空内容
可设置自定义展示空内容
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}
/>
);
};
API 参考
属性 | 说明 | 类型 | 默认值 | 版本 |
---|
autoFocus | 是否自动聚焦 | bool | false | 1.16.0 |
autoAdjustOverflow | 浮层被遮挡时是否自动调整方向 | bool | true | |
className | 样式类名 | string | | |
clearIcon | 可用于自定义清除按钮, showClear为true时有效 | ReactNode | | 2.25.0 |
data | 候选项的数据源,可以为字符串数组或对象数组 | array | [] | |
defaultActiveFirstOption | 是否默认高亮第一个选项(按回车可直接选中) | bool | false | |
defaultOpen | 是否默认展开下拉菜单 | boolean | false | |
defaultValue | 默认值 | string | | |
disabled | 是否禁用 | boolean | false | |
dropdownClassName | 下拉列表的 CSS 类名 | string | | |
dropdownStyle | 下拉列表的内联样式 | object | | |
emptyContent | data 为空时自定义下拉内容 | ReactNode | null | 1.16.0 |
getPopupContainer | 指定下拉列表浮层的父级容器,浮层将会渲染至该 DOM 中。自定义该项时需给容器设置 position: relative 这会改变浮层 DOM 树位置,但不会改变视图渲染位置 | () => HTMLElement | () => document.body | |
loading | 下拉列表是否展示加载动画 | boolean | false | |
maxHeight | 下拉列表的最大高度 | number|string | 300 | |
motion | 下拉列表出现/隐藏时,是否有动画 | boolean | true | |
onSelectWithObject | 点击候选项时,是否将选中项 option 的其他属性也作为回调入参。设为 true 时,onSelect 的入参类型会从 string 变为 object: { value, label, ...rest } | boolean | false | 1.23.0 |
placeholder | 输入框默认提示文案 | string | | |
position | 下拉菜单的显示位置,可选值同 tooltip 组件 | string | 'bottomLeft' | |
prefix | 选择框的前缀标签 | ReactNode | | 0.23.0 |
renderItem | 控制下拉列表候选项的渲染 | (option: string|Item)=> React.Node | | |
renderSelectedItem | 通过 renderSelectedItem 自定义下拉列表候选项被点击选中后,在选择框中的渲染内容 仅支持 String 类型的返回值
| (option: string|Item) => string | | |
showClear | 是否展示清除按钮 | boolean | false | |
size | 尺寸,可选small , default , large | string | default | |
style | 样式 | object | | |
suffix | 选择框的前缀标签 | ReactNode | | |
validateStatus | 校验状态,可选值default 、error 、warning ,默认 default。仅影响展示样式 | string | 'default' | 1.14.0 |
value | 当前值 | string|number | 无 | |
zIndex | 下拉菜单的 zIndex | number | | |
onBlur | 失去焦点时的回调 | Function(event) | | |
onChange | 输入框变化/候选项选中时变化 | Function(value:string|number) | | 1.23.0 |
onFocus | 获得焦点时的回调 | Function(event) | | |
onKeyDown | keydown 回调 | (e: React.KeyboardEvent) => void | | 2.21.0 |
onSearch | 输入变化时的回调 | Function(value: string) | | |
onSelect | 下拉菜单候选项被选中时的回调 | Function(item: string|number|Item) | | |
Accessibility
键盘和焦点
- AutoComplete 的 input 框可被聚焦,聚焦后,键盘用户可以通过
上箭头
或 下箭头
打开选项面板(如有) - AutoComplete 也支持通过
Enter
键打开和收起面板 - 若用户将 defaultActiveFirstOption 属性设置为 true 时,选项面板打开后默认高亮第一个选项
- 若下拉菜单打开时:
- 使用
Esc
可以关闭菜单 - 使用
上箭头
或 下箭头
可以切换选项 - 被聚焦的选项可以通过
Enter
键选中,并收起面板
文案规范
- 需要清晰地展示内容,让用户显而易见地感知到可用的各个选项
- 限制一次性展示的选项数量