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
两种属性的组合。 这个状态展示了在文本框中显示的值。
任意输入
Set freeSolo
to true so the textbox can contain any arbitrary value.
搜索输入栏
The prop is designed to cover the primary use case of a search input with suggestions, e.g. Google search or react-autowhatever.
自由创造
If you intend to use this mode for a combo box like experience (an enhanced version of a select element) we recommend setting:
selectOnFocus
可以帮助用户清除所选定的值。clearOnBlur
可以帮助用户输入一个新值。handleHomeEndKeys
使用Home 和 End 键在弹出窗口内移动焦点。- 最后一个选项,例如
加上 "你的搜索结果"
。
You could also display a dialog when the user wants to add a new value.
分组
You can group the options with the groupBy
prop. If you do so, make sure that the options are also sorted with the same dimension that they are grouped by, otherwise, you will notice duplicate headers.
<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
For advanced customization use cases, a headless useAutocomplete()
hook is exposed. It accepts almost the same options as the Autocomplete component minus all the props related to the rendering of JSX. The Autocomplete component is built on this hook.
import { useAutocomplete } from '@mui/base/AutocompleteUnstyled';
The useAutocomplete
hook is also reexported from @mui/material for convenience and backward compatibility.
import useAutocomplete from '@mui/material/useAutocomplete';
Head to the customization section for an example with the Autocomplete
component instead of the hook.
异步请求
The component supports two different asynchronous use-cases:
- 打开时加载:它将等待用户与组件进行交互以加载选项。
- 当你键入内容时进行搜索:每一次键入都会提交一个新的请求。
打开时加载
It displays a progress state as long as the network request is pending.
当你键入内容时进行搜索
If your logic is fetching new options on each keystroke and using the current value of the textbox to filter on the server, you may want to consider throttling requests.
Additionally, you will need to disable the built-in filtering of the Autocomplete
component by overriding the filterOptions
prop:
<Autocomplete filterOptions={(x) => x} />
Google Maps Places
A customized UI for Google Maps Places Autocomplete. For this demo, we need to load the Google Maps JavaScript and Google Places API.
固定的选项
In the event that you need to lock certain tags so that they can't be removed, you can set the chips disabled.
<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" />
)}
sx={{ width: '500px' }}
/>
个性化
自定义输入
The renderInput
prop allows you to customize the rendered input. The first argument of this render prop contains props that you need to forward. Pay specific attention to the ref
and inputProps
keys.
Head to the Customized hook section for a customization example with the useAutocomplete
hook instead of the component.
高亮显示
The following demo relies on autosuggest-highlight, a small (1 kB) utility for highlighting text in autosuggest and autocomplete components.
自定义筛选
The component exposes a factory to create a filter method that can be provided to the filterOptions
prop. You can use it to change the default option filter behavior.
import matchSorter from 'match-sorter';
const filterOptions = (options, { inputValue }) => matchSorter(options, inputValue);
<Autocomplete filterOptions={filterOptions} />;
createFilterOptions(config) => filterOptions
参数
config
(object [optional]):
config.ignoreAccents
(bool [optional]):默认为true
。 移除字母的变音符号。config.ignoreCase
(bool [optional]):默认为true
。 所有字母都小写。config.limit
(number [optional]): 默认值为 null。 显示限定数量的建议选项。 例如,如果config.limit
是100
,,那么只显示前100 个
匹配的选项。 如果存在很多选项匹配,并且虚拟化设置还没建立成时,这样的限制是非常有效的。config.matchFrom
('any' | 'start' [optional]): 默认值为'any'
。config.stringify
(func [optional]): 控制如何将一个选项转换成一个字符串,这样,选项就能够和输入文本的片段相匹配。config.trim
(bool [optional]):默认为false
。 删除尾随空格。
返回结果
filterOptions
: the returned filter method can be provided directly to the filterOptions
prop of the Autocomplete
component, or the parameter of the same name for the hook.
In the following demo, the options need to start with the query prefix:
const filterOptions = createFilterOptions({
matchFrom: 'start',
stringify: (option) => option.title,
});
<Autocomplete filterOptions={filterOptions} />;
进阶使用
For richer filtering mechanisms, like fuzzy matching, it's recommended to look at match-sorter. For instance:
import { matchSorter } from 'match-sorter';
const filterOptions = (options, { inputValue }) => matchSorter(options, inputValue);
<Autocomplete filterOptions={filterOptions} />;
虚拟滚动
Search within 10,000 randomly generated options. The list is virtualized thanks to react-window.
<Autocomplete
id="virtualize-demo"
sx={{ width: 300 }}
disableListWrap
PopperComponent={StyledPopper}
ListboxComponent={ListboxComponent}
options={OPTIONS}
groupBy={(option) => option[0].toUpperCase()}
renderInput={(params) => <TextField {...params} label="10,000 options" />}
renderOption={(props, option) => [props, option] as React.ReactNode}
// TODO: Post React 18 update - validate this conversion, look like a hidden bug
renderGroup={(params) => params as unknown as React.ReactNode}
/>
事件
If you would like to prevent the default key handler behavior, you can set the event's defaultMuiPrevented
property to true
:
<Autocomplete
onKeyDown={(event) => {
if (event.key === 'Enter') {
// Prevent's default 'Enter' behavior.
event.defaultMuiPrevented = true;
// your handler code
}
}}
/>
设计局限
autocomplete/autofill
Browsers have heuristics to help the user fill in form inputs. However, this can harm the UX of the component.
By default, the component disables the input autocomplete feature (remembering what the user has typed for a given field in a previous session) with the autoComplete="off"
attribute. Google Chrome does not currently support this attribute setting (Issue 587466). A possible workaround is to remove the id
to have the component generate a random one.
In addition to remembering past entered values, the browser might also propose autofill suggestions (saved login, address, or payment details). In the event you want the avoid autofill, you can try the following:
给输入框一个不同的名字,这样不会给浏览器泄露任何可以滥用的信息。 例如:
id="field1"
而不是id="country"
。 若你不填写 id 的话,该组件则会使用一个随机的 id。设置
autoComplete="new-password"
(当设置此属性时,有些浏览器会建议输入高复杂度的密码)。<TextField {...params} inputProps={{ ...params.inputProps, autoComplete: 'new-password', }} />
Read the guide on MDN for more details.
iOS VoiceOver 辅助功能
VoiceOver on iOS Safari doesn't support the aria-owns
attribute very well. You can work around the issue with the disablePortal
prop.
ListboxComponent
If you provide a custom ListboxComponent
prop, you need to make sure that the intended scroll container has the role
attribute set to listbox
. This ensures the correct behavior of the scroll, for example when using the keyboard to navigate.
无障碍设计
(WAI-ARIA: https://www.w3.org/WAI/ARIA/apg/patterns/combobox/)
We encourage the usage of a label for the textbox. The component implements the WAI-ARIA authoring practices.