Autocomplete 自动补全组件
自动补全是一个普通文本输入框,它通过一组建议的选项来帮助用户输入。
该组件常用于以下两个场景中的单行文本框赋值:
- 文本框必须取值于某个预设好的,例如:一个位置域必须包含一个有效的位置名称: 组合框。
- 文本框也可以是任何值,但最好能够为用户提供可能的选项,譬如搜索框可以提供近似的或者曾搜索过的选项以节省用户时间:灵活的单文本框。
此组件旨在改进 “react-select” 和 “downshift” 这两个包。
Combo box 组合框
必须取值于一个预设的可选数据源。
<Autocomplete
id="combo-box-demo"
options={top100Films}
getOptionLabel={(option) => option.title}
style={{ width: 300 }}
renderInput={(params) => <TextField {...params} label="Combo box" variant="outlined" />}
/>
可控的状态
此组件有两种可控的状态:
- “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}
style={{ width: 300 }}
renderInput={(params) => <TextField {...params} label="With categories" variant="outlined" />}
/>
<Autocomplete
id="disabled-options-demo"
options={timeSlots}
getOptionDisabled={(option) => option === timeSlots[0] || option === timeSlots[2]}
style={{ width: 300 }}
renderInput={(params) => (
<TextField {...params} label="Disabled options" variant="outlined" />
)}
/>
useAutocomplete
对于高级定制用例,我们暴露了一个无头(headless)的 useAutocomplete()
hook。 它接受几乎与 Autocomplete 组件相同的参数,辅以与 JSX 渲染有关的所有参数。 Autocomplete 组件内部也是使用的此 hook。
import useAutocomplete from '@material-ui/lab/useAutocomplete';
- 📦 4.5kB 的压缩包。
请转到 自定义自动完成组件 的部分,来查看使用 Autocomplete
组件(而不是 hook)的例子。
异步请求
在这个演示中,我们需要加载 [谷歌地图 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} variant="outlined" label="limitTags" placeholder="Favorites" />
)}
/>
个性化
自定义输入
使用 renderInput
属性,您可以对输入内容进行自定义渲染。 此 render 属性的第一个参数包含了你想要传递的那些属性。 请特别注意 ref
和 inputProps
键(key)。
<Autocomplete
id="custom-input-demo"
options={options}
renderInput={(params) => (
<div ref={params.InputProps.ref}>
<input style={{ width: 200 }} type="text" {...params.inputProps} />
</div>
)}
/>
你也可以转到自定义 hook 章节,查看一下使用 useAutocomplete
hook 的自定义例子,而不是使用组件。
高亮显示
以下的例子通过 autosuggest-highlight 这个小型(1 kB)的插件来实现自动推荐和自动补全组件中的高亮文字。
自定义筛选
此组件提供了一个 factory 来构建一个筛选的方法,供给 filterOptions
属性使来用。 用此你可以更改默认的筛选行为。
import { createFilterOptions } from '@material-ui/lab/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"
style={{ width: 300 }}
disableListWrap
classes={classes}
ListboxComponent={ListboxComponent}
renderGroup={renderGroup}
options={OPTIONS}
groupBy={(option) => option[0].toUpperCase()}
renderInput={(params) => <TextField {...params} variant="outlined" label="10,000 options" />}
renderOption={(option) => <Typography noWrap>{option}</Typography>}
/>
设计局限
autocomplete/autofill
浏览器会有启发性的帮助用户填写表格。 然而,这样的功能会削弱的组件用户体验。
默认情况下,组件通过 autoComplete="off"
这个属性,禁用了 autocomplete 功能(请注意用户可能在之前已经在给定域输入内容)。
然而,除了记住过去已经输入的值,浏览器可能也会给出 自动填充(autofill) 的建议(譬如有保存的登录信息,地址,或者支付方式等)。 若您不需要自动填充,您可以尝试以下的方式:
- 给输入框一个不同的名字,这样不会给浏览器泄露任何可以滥用的信息。 例如:
id="field1"
而不是id="country"
。 若你不填写 id 的话,该组件则会使用一个随机的 id。 - 设置为
autoComplete="new-password"
:jsx <TextField {...params} inputProps={{ ...params.inputProps, autoComplete: 'new-password', }} />
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 授权的一些标准。