Autocomplete 自动补全组件
自动补全是一个普通文本输入框,它通过一组建议的选项来帮助用户输入。
该组件常用于以下两个场景中的单行文本框赋值:
- 文本框必须取值于某个预设好的,例如:一个位置域必须包含一个有效的位置名称: 组合框。
- 文本框也可以是任何值,但最好能够为用户提供可能的选项,譬如搜索框可以提供近似的或者曾搜索过的选项以节省用户时间:灵活的单文本框。
此组件旨在改进 “react-select” 和 “downshift” 这两个包。
<Autocomplete
disablePortal
id="combo-box-demo"
options={top100Films}
sx={{ width: 300 }}
renderInput={(params) => <TextField {...params} label="Movie" />}
/>
选项结构
默认情况下,该组件接受和以下结构相同的选项:
interface AutocompleteOption {
label: string;
}
// 或者
type AutocompleteOption = string;
例如:
const options = [
{ label: 'The Godfather', id: 1 },
{ label: 'Pulp Fiction', id: 2 },
];
// or
const options = ['The Godfather', 'Pulp Fiction'];
然而,你也可以通过提供 getOptionLabel
属性来使用不同的结构。
练习
以下每个示例演示了自动补全组件的单项功能。
可控的状态
此组件有两种可控的状态:
- “value” 状态(state)包含了
value
/onChange
两种属性的组合。 这个状态表示用户选择的值,如当按下 Enter 键时。 - “input value” 状态(state) 则包含了
inputValue
/onInputChange
两种属性的组合。 这个状态展示了在文本框中显示的值。
⚠️ 以上两种状态互不干涉,它们应该被单独控制着。
Free solo
当将 freeSolo
设置为 true 时,用户可以文本框中输入任意值。
搜索输入栏
该属性的主要使用方式是创建一个带有搜索建议的 输入文本框,例如 Google 搜索 或 react-autowhatever。
Creatable (可创造性)
如果您打算将此模块用于类似 组合框 的体验(一个选择控件元素的增强版),我们则建议如下的设置:
selectOnFocus
帮助用户清除所选值。clearOnBlur
帮助用户输入一个新的值。handleHomeEndKeys
使用Home 和 End 键在弹出窗口内移动焦点。- 最后一个选项,例如
加上 "你的搜索结果"
。
您也可以在用户想要加入一个新值的时候显示一个对话框。
<Autocomplete
id="grouped-demo"
options={options.sort((a, b) => -b.firstLetter.localeCompare(a.firstLetter))}
groupBy={(option) => option.firstLetter}
getOptionLabel={(option) => option.title}
sx={{ width: 300 }}
renderInput={(params) => <TextField {...params} label="With categories" />}
/>
<Autocomplete
id="disabled-options-demo"
options={timeSlots}
getOptionDisabled={(option) =>
option === timeSlots[0] || option === timeSlots[2]
}
sx={{ width: 300 }}
renderInput={(params) => <TextField {...params} label="Disabled options" />}
/>
useAutocomplete
对于高级定制用例,我们暴露了一个无头(headless)的 useAutocomplete()
hook。 它接受几乎与 Autocomplete 组件相同的参数,辅以与 JSX 渲染有关的所有参数。 Autocomplete 组件内部也是使用的此 hook。
import useAutocomplete from '@material-ui/core/useAutocomplete';
- 📦 4.5kB 的压缩包。
请前往 自定义 部分,查看使用 自动完成
组件代替 hook 的示例。
异步请求
该组件对异步使用有两种不同的案例:
- 打开时加载:它将等待用户与组件进行交互以加载选项。
- 当你键入内容时进行搜索:每一次键入都会提交一个新的请求。
打开时加载
只要网络请求正在等待,它就会显示进度状态。
当你键入内容时进行搜索
如果你的逻辑是在每次键入内容时就获取新的选项,并使用文本框的当前值在服务器上进行筛选,那么则可能需要考虑限制请求速率。
此外,你需要通过覆盖 filterOptions
属性来禁用 Autocomplete
组件的内置过滤功能。
<Autocomplete filterOptions={(x) => x} />
Google Maps Places
一个为 Google Maps Places 自动补全功能设计的 UI。
在这个演示中,我们需要加载 [谷歌地图 JavaScript](https://developers. google. com/maps/documentation/javascript/tutorial) 的 API。
⚠️在你开始使用 Google Maps JavaScript API 之前,你必须注册并且创建一个可支付的账户。
多个值
这也称为标签(tags),用户可以输入多个的值。
<Autocomplete
multiple
limitTags={2}
id="multiple-limit-tags"
options={top100Films}
getOptionLabel={(option) => option.title}
defaultValue={[top100Films[13], top100Films[12], top100Films[11]]}
renderInput={(params) => (
<TextField {...params} label="limitTags" placeholder="Favorites" />
)}
/>
Customization 个性化
自定义输入
使用 renderInput
属性,您可以对输入内容进行自定义渲染。 此 render 属性的第一个参数包含了你想要传递的那些属性。 请特别注意 ref
和 inputProps
键(key)。
你也可以转到自定义 hook 章节,查看一下使用 useAutocomplete
hook 的自定义例子,而不是使用组件。
高亮显示
以下的例子通过 autosuggest-highlight 这个小型(1 kB)的插件来实现自动推荐和自动补全组件中的高亮文字。
自定义筛选
此组件提供了一个 factory 来构建一个筛选的方法,供给 filterOptions
属性使来用。 用此你可以更改默认的筛选行为。
import { createFilterOptions } from '@material-ui/core/Autocomplete';
createFilterOptions(config) => filterOptions
参数
config
(Object [optional]):
config.ignoreAccents
(Boolean [optional]):默认值为true
。 移除字母的变音符号。config.ignoreCase
(Boolean [optional]): 默认值为true
。 所有字母都小写。config.limit
(Number [optional]): 默认值为 null。 显示限定数量的建议选项。 例如,如果config.limit
是100
,,那么只显示前100 个
匹配的选项。 如果存在很多选项匹配,并且虚拟化设置还没建立成时,这样的限制是非常有效的。config.matchFrom
('any' | 'start' [optional]): 默认值为'any'
。config.stringify
(Func [optional]): 控制如何将一个选项转换成一个字符串,这样选项就能够和输入文本的片段相匹配。config.trim
(Boolean [optional]): 默认值为false
。 删除尾随空格。
返回结果
过滤选项
:返回的过滤器方法可以直接提供给 Autocomplete
组件的 filterOptions
属性, 或者可以传给 hook 的同名参数。
在以下的例子中,选项必须有一个查询的前缀:
const filterOptions = createFilterOptions({
matchFrom: 'start',
stringify: (option) => option.title,
});
<Autocomplete filterOptions={filterOptions} />;
Advanced 进阶
对于更复杂的过滤机制,譬如模糊匹配(fuzzy matching),我们推荐您看一下 match-sorter。 就像这样:
import matchSorter from 'match-sorter';
const filterOptions = (options, { inputValue }) => matchSorter(options, inputValue);
<Autocomplete filterOptions={filterOptions} />;
可视化
在 10000 个随机生成的选项中搜索。 多亏了react-window,这个列表得以可视化。
<Autocomplete
id="virtualize-demo"
sx={{ width: 300 }}
disableListWrap
PopperComponent={StyledPopper}
ListboxComponent={ListboxComponent}
renderGroup={renderGroup}
options={OPTIONS}
groupBy={(option) => option[0].toUpperCase()}
renderInput={(params) => <TextField {...params} label="10,000 options" />}
renderOption={(props, option) => (
<li {...props}>
<Typography noWrap>{option}</Typography>
</li>
)}
/>
事件
如果你不想要浏览器自动填充密钥,那么你可以将事件的 defaultMuiPrevented
属性设置为 true
。
<Autocomplete
onKeyDown={(event) => {
if (event.key === 'Enter') {
// 阻止默认的“Enter”行为。
event.defaultMuiPrevented = false;
// 你的处理器代码
}
}}
/>
设计局限
autocomplete/autofill
浏览器会有启发性的帮助用户填写表格。 然而,这样的功能会削弱的组件用户体验。
默认情况下,组件将会使用 autoComplete="off"
属性来禁用 autocomplete 功能(记住用户在之前的会话中为某个字段输入的内容)。 Google Chrome 浏览器目前不支持此属性设置(Issue 587466)。 要解决这个问题,可以采用的变通方法是删除 id
,让组件自行随机生成。
除了记住过去输入的值,浏览器还可能发出 自动填写(autofill)建议(保存的登录名、地址或支付详情)。 若您不需要自动填充,您可以尝试以下的方式:
给输入框一个不同的名字,这样不会给浏览器泄露任何可以滥用的信息。 例如:
id="field1"
而不是id="country"
。 若你不填写 id 的话,该组件则会使用一个随机的 id。设置
autoComplete="new-password"
(当设置此属性时,有些浏览器会建议输入高复杂度的密码)。<TextField {...params} inputProps={{ ...params.inputProps, autoComplete: 'new-password', }} />
请阅读 这篇 MDN 指南 来寻求更多解决方案。
iOS VoiceOver 辅助功能
iOS Safari 中的 VoiceOver 对 aria-owns
属性的支持并不是很到位。 你可以用 disablePortal
属性来解决这个问题。
ListboxComponent
若你提供一共自定义的 ListboxComponent
属性,请保证需要滚动功能的容器将 role
属性设置为 listbox
。 这能保证滚动功能在一些情况下,例如当用键盘切换的时候,仍然能够正常显示。
无障碍设计
(WAI-ARIA: https://www.w3.org/TR/wai-aria-practices/#combobox)
我们鼓励用户在 textbox 中使用标签。 组件带入了 WAI-ARIA 授权的一些标准。