Skip to main content

Bài 13-Tự động hoàn thành

Tính năng tự động hoàn thành là chức năng nhập văn bản thông thường được cải tiến bằng bảng tùy chọn gợi ý.giàn giáoScaffoldHub . Tự động xây dựng ứng dụng web Material UI đầy đủ của bạn.quảng cáo của MUI

Tiện ích này hữu ích khi thiết lập giá trị của hộp văn bản một dòng trong một trong hai trường hợp sau:

  1. Giá trị cho hộp văn bản phải được chọn từ một tập hợp các giá trị được phép được xác định trước, ví dụ trường vị trí phải chứa tên vị trí hợp lệ: hộp kết hợp .
  2. Hộp văn bản có thể chứa bất kỳ giá trị tùy ý nào, nhưng sẽ có lợi hơn nếu gợi ý các giá trị có thể cho người dùng, ví dụ trường tìm kiếm có thể gợi ý các tìm kiếm tương tự hoặc trước đó để tiết kiệm thời gian cho người dùng: free solo .

Đây được coi là phiên bản cải tiến của các gói "react-select" và "downshift".

Hộp kết hợp

Giá trị phải được chọn từ một tập hợp các giá trị được phép được xác định trước.

Bộ phim

Bộ phim

Mở rộng mã

<Autocomplete
disablePortal
options={top100Films}
sx={{ width: 300 }}
renderInput={(params) => <TextField {...params} label="Movie" />}
/>

Nhấn Enterđể bắt đầu chỉnh sửa

Cấu trúc tùy chọn

Theo mặc định, thành phần này chấp nhận các cấu trúc tùy chọn sau:

interface AutocompleteOption {
label: string;
}
// or
type AutocompleteOption = string;

Sao chép

ví dụ:

const options = [
{ label: 'The Godfather', id: 1 },
{ label: 'Pulp Fiction', id: 2 },
];
// or
const options = ['The Godfather', 'Pulp Fiction'];

Sao chép

Tuy nhiên, bạn có thể sử dụng các cấu trúc khác nhau bằng cách cung cấp getOptionLabelđạo cụ.

Nếu tùy chọn của bạn là đối tượng, bạn phải cung cấp isOptionEqualToValueprop để đảm bảo lựa chọn và tô sáng chính xác. Theo mặc định, nó sử dụng tính bình đẳng nghiêm ngặt để so sánh các tùy chọn với giá trị hiện tại.

Sân chơi

Mỗi ví dụ sau đây minh họa một tính năng của thành phần Tự động hoàn thành.

vô hiệu hóaĐóngTrênChọn

xóaOnEscape

vô hiệu hóaCó thể xóa

bao gồmInputInList

phẳng

được kiểm soát

tự động hoàn thành

vô hiệu hóaListWrap

mởOnFocus

tự động làm nổi bật

tự động chọn

tàn tật

vô hiệu hóaPortal

blurOnSelect

xóaBị mờ

chọnOnFocus

Chỉ đọc

Hiển thị mã

Chọn quốc gia

Chọn một trong 248 quốc gia.

Chọn một quốc gia

Chọn một quốc gia

Hiển thị mã

Các trạng thái được kiểm soát

Thành phần này có hai trạng thái có thể được kiểm soát:

  1. trạng thái "giá trị" với tổ hợp props valueonChange. Trạng thái này biểu thị giá trị do người dùng chọn, ví dụ khi nhấn Enter.
  2. trạng thái "giá trị đầu vào" với tổ hợp props inputValueonInputChange. Trạng thái này biểu thị giá trị được hiển thị trong hộp văn bản.

Hai trạng thái này là riêng biệt và cần được kiểm soát độc lập.

  • Một thành phần được kiểm soát khi nó được quản lý bởi thành phần cha bằng cách sử dụng props.
  • Một thành phần không được kiểm soát khi nó được quản lý bởi trạng thái cục bộ của chính nó.

Tìm hiểu thêm về các thành phần được kiểm soát và không được kiểm soát trong tài liệu React .

giá trị: 'Tùy chọn 1'

inputValue: 'Tùy chọn 1'

Có thể kiểm soát được

Có thể kiểm soát được

Hiển thị mã

Nếu bạn kiểm soát value, hãy đảm bảo nó ổn định về mặt tham chiếu giữa các lần kết xuất. Nói cách khác, tham chiếu đến giá trị không nên thay đổi nếu giá trị đó không thay đổi.

// ⚠️ BAD
return <Autocomplete multiple value={allValues.filter((v) => v.selected)} />;

// 👍 GOOD
const selectedValues = React.useMemo(
() => allValues.filter((v) => v.selected),
[allValues],
);
return <Autocomplete multiple value={selectedValues} />;

Sao chép

Trong ví dụ đầu tiên, allValues.filterđược gọi và trả về một mảng mới mỗi lần render. Bản sửa lỗi bao gồm việc ghi nhớ giá trị, do đó nó chỉ thay đổi khi cần thiết.

Đơn tự do

Đặt freeSolothành true để hộp văn bản có thể chứa bất kỳ giá trị tùy ý nào.

Tìm kiếm đầu vào

Prop được thiết kế để bao gồm trường hợp sử dụng chính của đầu vào tìm kiếm với các gợi ý, ví dụ như tìm kiếm Google hoặc react-autowhatever.

miễn phíSolo

miễn phíSolo

Tìm kiếm đầu vào

Tìm kiếm đầu vào

Hiển thị mã

Hãy cẩn thận khi sử dụng chế độ solo miễn phí với các tùy chọn không phải chuỗi, vì nó có thể gây ra sự không khớp kiểu.

Giá trị được tạo ra bằng cách nhập vào hộp văn bản luôn là một chuỗi, bất kể loại tùy chọn nào.

Có thể tạo ra

Nếu bạn định sử dụng chế độ này cho hộp kết hợp như trải nghiệm (phiên bản nâng cao của phần tử chọn), chúng tôi khuyên bạn nên thiết lập:

  • selectOnFocusđể giúp người dùng xóa giá trị đã chọn.
  • clearOnBlurđể giúp người dùng nhập giá trị mới.
  • handleHomeEndKeysđể di chuyển tiêu điểm bên trong cửa sổ bật lên bằng phím Homevà End.
  • Một lựa chọn cuối cùng, ví dụ: Add "YOUR SEARCH".

Bản demo solo miễn phí có kèm văn bản

Bản demo solo miễn phí có kèm văn bản

Hiển thị mã

Bạn cũng có thể hiển thị hộp thoại khi người dùng muốn thêm giá trị mới.

Đối thoại solo miễn phí

Đối thoại solo miễn phí

Hiển thị mã

Nhóm lại

Bạn có thể nhóm các tùy chọn với groupByprop. Nếu bạn làm như vậy, hãy đảm bảo rằng các tùy chọn cũng được sắp xếp theo cùng kích thước mà chúng được nhóm theo, nếu không, bạn sẽ thấy các tiêu đề trùng lặp.

Với các danh mục

Với các danh mục

Mở rộng mã

<Autocomplete
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" />}
/>

Nhấn Enterđể bắt đầu chỉnh sửa

Để kiểm soát cách các nhóm được hiển thị, hãy cung cấp một renderGroupprop tùy chỉnh. Đây là một hàm chấp nhận một đối tượng có hai trường:

  • group—một chuỗi đại diện cho tên nhóm
  • children—một tập hợp các mục danh sách thuộc về nhóm

Bản demo sau đây cho thấy cách sử dụng thuộc tính này để xác định đánh dấu tùy chỉnh và ghi đè lên kiểu của các nhóm mặc định:

Với các danh mục

Với các danh mục

Mở rộng mã

<Autocomplete
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" />}
renderGroup={(params) => (
<li key={params.key}>
<GroupHeader>{params.group}</GroupHeader>
<GroupItems>{params.children}</GroupItems>
</li>
)}
/>

Nhấn Enterđể bắt đầu chỉnh sửa

Tùy chọn bị vô hiệu hóa

Tùy chọn bị vô hiệu hóa

Tùy chọn bị vô hiệu hóa

Mở rộng mã

<Autocomplete
options={timeSlots}
getOptionDisabled={(option) =>
option === timeSlots[0] || option === timeSlots[2]
}
sx={{ width: 300 }}
renderInput={(params) => <TextField {...params} label="Disabled options" />}
/>

Nhấn Enterđể bắt đầu chỉnh sửa

useAutocomplete

Đối với các trường hợp sử dụng tùy chỉnh nâng cao, một useAutocomplete()hook không có đầu được hiển thị. Nó chấp nhận hầu như cùng các tùy chọn như thành phần Tự động hoàn thành trừ tất cả các thuộc tính liên quan đến việc hiển thị JSX. Thành phần Tự động hoàn thành được xây dựng trên hook này.

import { useAutocomplete } from '@mui/base/useAutocomplete';

Sao chép

Hook useAutocompletecũng được xuất lại từ @mui/material để thuận tiện và tương thích ngược.

import useAutocomplete from '@mui/material/useAutocomplete';

Sao chép

sử dụngTự động hoàn thành

Hiển thị mã

Móc tùy chỉnh

Móc tùy chỉnh

Bố già

Hiển thị mã

Hãy chuyển đến phần tùy chỉnh để xem ví dụ về Autocompletethành phần thay vì móc.

Yêu cầu không đồng bộ

Thành phần này hỗ trợ hai trường hợp sử dụng không đồng bộ khác nhau:

Tải về mở

Nó hiển thị trạng thái tiến trình miễn là yêu cầu mạng vẫn đang chờ xử lý.

Không đồng bộ

Không đồng bộ

Hiển thị mã

Tìm kiếm khi bạn nhập

Nếu logic của bạn là tìm nạp các tùy chọn mới trên mỗi lần nhấn phím và sử dụng giá trị hiện tại của hộp văn bản để lọc trên máy chủ, bạn có thể cân nhắc việc hạn chế các yêu cầu.

Ngoài ra, bạn sẽ cần phải vô hiệu hóa chức năng lọc tích hợp của Autocompletethành phần bằng cách ghi đè filterOptionsthuộc tính:

<Autocomplete filterOptions={(x) => x} />

Sao chép

Địa điểm Google Maps

Giao diện người dùng tùy chỉnh cho Google Maps Places Autocomplete. Đối với bản demo này, chúng ta cần tải Google Maps JavaScript và Google Places API.

Bản demo sau đây dựa trên autosuggest-highlight , một tiện ích nhỏ (1 kB) để làm nổi bật văn bản trong các thành phần autosuggest và autocomplete.

Thêm vị trí

Thêm vị trí

Hiển thị mã

Trước khi bạn có thể bắt đầu sử dụng Google Maps JavaScript API và Places API, bạn cần có khóa API của riêng mình .

Nhiều giá trị

Còn được gọi là thẻ, người dùng được phép nhập nhiều hơn một giá trị.

Nhiều giá trị

Sự khởi đầu

lọcChọnTùy chọn

Sự khởi đầu

lọcChọnTùy chọn

miễn phíSolo

Sự khởi đầu

Chỉ đọc

Forrest Gump

Sự khởi đầu

Chỉ đọc

Hiển thị mã

Tùy chọn cố định

Trong trường hợp bạn cần khóa một số thẻ nhất định để chúng không thể bị gỡ bỏ, bạn có thể tắt chip.

Thẻ cố định

Tiểu thuyết giật gân

Sự khởi đầu

Thẻ cố định

Hiển thị mã

Hộp kiểm

Hộp kiểm

Hộp kiểm

Hiển thị mã

Giới hạn thẻ

Bạn có thể sử dụng limitTagsđạo cụ để giới hạn số lượng tùy chọn hiển thị khi không được tập trung.

giới hạnTags

Sự khởi đầu

Forrest Gump

+1

giới hạnTags

Mở rộng mã

<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' }}
/>

Nhấn Enterđể bắt đầu chỉnh sửa

Kích thước

Bạn muốn đầu vào nhỏ hơn? Hãy sử dụng sizeprop.

Kích thước nhỏ

Kích thước nhỏ

Sự khởi đầu

Kích thước nhỏ

Kích thước nhỏ

Kích thước nhỏ

Sự khởi đầu

Kích thước nhỏ

Kích thước nhỏ

Kích thước nhỏ

Sự khởi đầu

Hiển thị mã

Tùy chỉnh

Đầu vào tùy chỉnh

Prop renderInputcho phép bạn tùy chỉnh đầu vào được render. Đối số đầu tiên của render prop này chứa các prop mà bạn cần chuyển tiếp. Hãy chú ý cụ thể đến các phím refvà inputProps.

Nếu bạn đang sử dụng thành phần đầu vào tùy chỉnh bên trong Tự động hoàn thành, hãy đảm bảo rằng bạn chuyển tiếp tham chiếu đến phần tử DOM cơ bản.

Giá trị: 

Hiển thị mã

Tùy chọn tùy chỉnh toàn cầu

Để tùy chỉnh toàn cầu các tùy chọn Tự động hoàn thành cho tất cả các thành phần trong ứng dụng của bạn, bạn có thể sử dụng các prop mặc định của chủ đề và đặt thuộc renderOptiontính trong defaultPropskhóa. renderOptionThuộc tính này lấy ownerStatetham số thứ tư, bao gồm các prop và trạng thái thành phần bên trong. Để hiển thị nhãn, bạn có thể sử dụng prop getOptionLabeltừ ownerState. Cách tiếp cận này cho phép các tùy chọn khác nhau cho mỗi thành phần Tự động hoàn thành trong khi vẫn giữ nguyên kiểu dáng của các tùy chọn.

Chọn một bộ phim

Chọn một quốc gia

Chọn một quốc gia

Mở rộng mã

<ThemeProvider theme={customTheme(outerTheme)}>
<Stack spacing={5} sx={{ width: 300 }}>
<MovieSelect />
<CountrySelect />
</Stack>
</ThemeProvider>

Nhấn Enterđể bắt đầu chỉnh sửa

Bộ chọn của GitHub

Bản demo này tái tạo trình chọn nhãn của GitHub:

Nhãn

cần giúp đỡ

loại: lỗi

Hiển thị mã

Đến phần Móc tùy chỉnh để biết ví dụ tùy chỉnh bằng useAutocompletemóc thay vì thành phần.

Gợi ý

Bản demo sau đây cho thấy cách thêm tính năng gợi ý vào tính năng Tự động hoàn thành:

Bộ phim

Bộ phim

Hiển thị mã

Điểm nổi bật

Bản demo sau đây dựa trên autosuggest-highlight , một tiện ích nhỏ (1 kB) để làm nổi bật văn bản trong các thành phần autosuggest và autocomplete.

Điểm nổi bật

Điểm nổi bật

Hiển thị mã

Bộ lọc tùy chỉnh

Thành phần này sẽ hiển thị một nhà máy để tạo phương thức lọc có thể được cung cấp cho filterOptionsprop. Bạn có thể sử dụng nó để thay đổi hành vi lọc tùy chọn mặc định.

import { createFilterOptions } from '@mui/material/Autocomplete';

Sao chép

createFilterOptions(config) => filterOptions

Lập luận

  1. configđối tượng [tùy chọn]):
  • config.ignoreAccentsbool [tùy chọn]): Mặc định là true. Xóa dấu phụ.
  • config.ignoreCasebool [tùy chọn]): Mặc định là true. Viết thường mọi thứ.
  • config.limitsố [tùy chọn]): Mặc định là null. Giới hạn số lượng tùy chọn được đề xuất sẽ hiển thị. Ví dụ, nếu config.limitlà 100, chỉ 100những tùy chọn khớp đầu tiên được hiển thị. Điều này có thể hữu ích nếu nhiều tùy chọn khớp và ảo hóa không được thiết lập.
  • config.matchFrom'bất kỳ' | 'bắt đầu' [tùy chọn]): Mặc định là 'any'.
  • config.stringifyfunc [tùy chọn]): Kiểm soát cách tùy chọn được chuyển đổi thành chuỗi để có thể khớp với đoạn văn bản đầu vào.
  • config.trimbool [tùy chọn]): Mặc định là false. Xóa khoảng trắng ở cuối.

Trả lại

filterOptions: phương thức lọc được trả về có thể được cung cấp trực tiếp cho filterOptionsprop của Autocompletethành phần hoặc tham số cùng tên cho hook.

Trong bản demo sau, các tùy chọn cần bắt đầu bằng tiền tố truy vấn:

const filterOptions = createFilterOptions({
matchFrom: 'start',
stringify: (option) => option.title,
});

<Autocomplete filterOptions={filterOptions} />;

Sao chép

Bộ lọc tùy chỉnh

Bộ lọc tùy chỉnh

Hiển thị mã

Trình độ cao

Đối với các cơ chế lọc phong phú hơn, như khớp mờ, bạn nên xem xét match-sorter . Ví dụ:

import { matchSorter } from 'match-sorter';

const filterOptions = (options, { inputValue }) => matchSorter(options, inputValue);

<Autocomplete filterOptions={filterOptions} />;

Sao chép

Ảo hóa

Tìm kiếm trong 10.000 tùy chọn được tạo ngẫu nhiên. Danh sách được ảo hóa nhờ react-window .

10.000 lựa chọn

10.000 lựa chọn

Mở rộng mã

<Autocomplete
sx={{ width: 300 }}
disableListWrap
options={OPTIONS}
groupBy={(option) => option[0].toUpperCase()}
renderInput={(params) => <TextField {...params} label="10,000 options" />}
renderOption={(props, option, state) =>
[props, option, state.index] as React.ReactNode
}
renderGroup={(params) => params as any}
slots={{
popper: StyledPopper,
listbox: ListboxComponent,
}}
/>

Nhấn Enterđể bắt đầu chỉnh sửa

Sự kiện

Nếu bạn muốn ngăn chặn hành vi xử lý phím mặc định, bạn có thể đặt defaultMuiPreventedthuộc tính của sự kiện thành true:

<Autocomplete
onKeyDown={(event) => {
if (event.key === 'Enter') {
// Prevent's default 'Enter' behavior.
event.defaultMuiPrevented = true;
// your handler code
}
}}
/>

Sao chép

Hạn chế

tự động hoàn thành/tự động điền

Trình duyệt có các thuật toán tìm kiếm để giúp người dùng điền thông tin vào biểu mẫu. Tuy nhiên, điều này có thể gây hại cho UX của thành phần.

Theo mặc định, thành phần vô hiệu hóa tính năng tự động hoàn thành đầu vào (ghi nhớ những gì người dùng đã nhập cho một trường nhất định trong phiên trước) bằng autoComplete="off"thuộc tính. Google Chrome hiện không hỗ trợ cài đặt thuộc tính này ( Sự cố 41239842 ). Một giải pháp thay thế khả thi là xóa idđể thành phần tạo ra một mục ngẫu nhiên.

Ngoài việc ghi nhớ các giá trị đã nhập trước đó, trình duyệt cũng có thể đề xuất các gợi ý tự động điền (thông tin đăng nhập đã lưu, địa chỉ hoặc thông tin thanh toán). Trong trường hợp bạn muốn tránh tự động điền, bạn có thể thử các cách sau:

  • Đặt tên cho đầu vào mà không làm rò rỉ bất kỳ thông tin nào mà trình duyệt có thể sử dụng. Ví dụ id="field1"thay vì id="country". Nếu bạn để id trống, thành phần sẽ sử dụng id ngẫu nhiên.

  • Thiết lập autoComplete="new-password"(một số trình duyệt sẽ gợi ý mật khẩu mạnh cho các mục nhập có cài đặt thuộc tính này):

    <TextField
    {...params}
    inputProps={{
    ...params.inputProps,
    autoComplete: 'new-password',
    }}
    />

    Sao chép

Đọc hướng dẫn trên MDN để biết thêm chi tiết.

iOS VoiceOver

VoiceOver trên iOS Safari không hỗ trợ aria-ownsthuộc tính này tốt lắm. Bạn có thể khắc phục sự cố bằng disablePortalprop.

Thành phần Listbox

Nếu bạn cung cấp một ListboxComponentprop tùy chỉnh, bạn cần đảm bảo rằng vùng chứa cuộn dự định có thuộc roletính được đặt thành listbox. Điều này đảm bảo hành vi chính xác của cuộn, ví dụ khi sử dụng bàn phím để điều hướng.

Khả năng tiếp cận

(WAI-ARIA: https://www.w3.org/WAI/ARIA/apg/patterns/combobox/ )

Chúng tôi khuyến khích sử dụng nhãn cho hộp văn bản. Thành phần này triển khai các hoạt động biên soạn WAI-ARIA.

Giao diện lập trình ứng dụng (API)

Xem tài liệu bên dưới để biết thông tin tham khảo đầy đủ về tất cả các thuộc tính và lớp có sẵn cho các thành phần được đề cập ở đây.