選擇器
Select 元件讓您可以建立選項列表,供使用者選擇。
簡介
選擇器是一種 UI 元素,可讓使用者從列表中選擇選項。
MUI Base 的 Select 元件取代了原生的 HTML <select>
標籤。它還包括 Option 元件,用於在列表中建立選項,以及 Option Group 用於將這些選項分組。
元件
import { Select } from '@mui/base/Select';
import { Option } from '@mui/base/Option';
以下範例示範如何建立和樣式化具有多個 Option 的 Select 元件
表單提交
在 Select 中選擇的值可以透過標準 HTML 表單提交到伺服器。
您可以自訂這個隱藏輸入框的值—詳情請參閱「物件值」章節。
TypeScript 注意事項
Select 的屬性是泛型的。由於 TypeScript 的限制,當將元件包裝在 forwardRef
(或其他高階元件) 中時,可能會導致非預期的行為。
在這種情況下,泛型參數將預設為 unknown
,且類型建議將不完整。為了避免這種情況,您可以手動將結果元件轉換為正確的類型
const CustomSelect = React.forwardRef(function CustomSelect<TValue>(
props: SelectProps<TValue>,
ref: React.ForwardedRef<HTMLUListElement>,
) {
// ...your code here...
return <Select {...props} ref={ref} />;
}) as <TValue>(
props: SelectProps<TValue> & React.RefAttributes<HTMLUListElement>,
) => React.JSX.Element;
為了簡潔起見,本文檔其餘的範例將不會使用 forwardRef
。
多重選擇
設定 multiple
屬性以讓使用者從列表中選擇多個選項。與單選模式相反,在選擇項目後,選項彈出視窗不會關閉,這讓使用者可以繼續選擇更多選項。
請注意,在多重選擇模式下,value
屬性 (和 defaultValue
) 是一個陣列。
受控選擇器
Select 可以用作非受控或受控元件。
選取的值10
使用 value
屬性來設定受控 Select 的值。非受控元件接受 defaultValue
,可用於設定初始值。若要取消選取所有值,請將 null
傳遞給相應的屬性。
物件值
Select 元件可以用於非字串值
選取的字元
{ "name": "Frodo", "race": "Hobbit" }
如果您在表單中使用具有物件值的 Select 並將表單內容提交到伺服器,則選取的值將會轉換為 JSON。您可以使用 getSerializedValue
屬性來變更此行為。
分組選項
import { OptionGroup } from '@mui/base/OptionGroup';
選項可以分組,類似於原生 <select>
元素的工作方式。與原生 <select>
不同,群組可以巢狀。
以下範例示範如何使用 Option Group 元件對 Option 進行分組
結構
Select 元件由一個根 <button>
以及一個 <div>
組成,該 <div>
在 Popup 內包含一個 <ul>
。Option 呈現為 <li>
,而 Option Group 則呈現一個 <ul>
,其中包含一個代表其標籤的 <li>
。
<button class="base-Select-root" type="button">Open</button>
<div class="base-Select-popup">
<ul class="base-Select-listbox">
<li class="base-Option-root">Option one</li>
<li class="base-Option-root">Option two</li>
</ul>
</div>
自訂結構
使用 slots
屬性來覆寫根或任何其他內部 slot
<Select slots={{ root: 'div', listbox: 'ol' }} />
使用 slotProps
屬性將自訂屬性傳遞到內部 slot。以下程式碼片段將名為 my-listbox
的 CSS 類別套用到 listbox slot
<Select slotProps={{ listbox: { className: 'my-listbox' } }} />
Portal
預設情況下,Select 的彈出視窗會在 Portal 中呈現,並附加到 DOM 的底部。若要改為在定義元件的位置呈現彈出視窗,請覆寫底層 Popup 的 disablePortal
屬性,如下所示
<Select slotProps={{ popup: { disablePortal: true } }} />
轉場效果
Select 元件支援Transitions API,因此可以為 Listbox 的出現和消失製作動畫效果。若要執行此操作,請覆寫 Select 的 Listbox slot,並使用轉場效果元件 (CssTransition、CssAnimation 或自訂建置的元件) 包裝它。
TypeScript 的用法
在 TypeScript 中,您可以將 slots.root
中使用的自訂元件類型指定為非樣式化元件的泛型參數。這樣,您就可以安全地直接在元件上提供自訂根的屬性
<Select<typeof CustomComponent> slots={{ root: CustomComponent }} customProp />
這同樣適用於特定於自訂原始元素的屬性
<Select<'button'> slots={{ root: 'button' }} onClick={() => {}} />
Hook
import { useSelect } from '@mui/base/useSelect';
useSelect
Hook 讓您可以將 Select 的功能應用於完全自訂的元件。它會傳回要放置在自訂元件上的屬性,以及表示元件內部狀態的欄位。
以下範例顯示使用 Hook 建置的選擇器。請注意,此元件不包含任何內建類別。與其預先建置的元件對應項相比,產生的 HTML 小得多,因為未套用類別名稱。
效能
useOption
Hook 監聽由父 Select 元件設定的 context 中的變更。每當項目被反白顯示時,此 context 就會變更。通常,這不應該是問題,但是,當您的選擇器有數百個選項時,您可能會注意到它不是很靈敏,因為每當反白顯示變更時,每個選項都會重新渲染。
若要透過防止選項不必要地渲染來改善效能,您可以建立一個包裝選項的元件。在此元件內部,呼叫 useOptionContextStabilizer
並使用 Hook 結果中的值建立 ListContext
const StableOption = React.forwardRef(function StableOption<OptionValue>(
props: OptionProps<OptionValue>,
ref: React.ForwardedRef<Element>,
) {
const { contextValue } = useOptionContextStabilizer(props.value);
return (
<ListContext.Provider value={contextValue}>
<Option {...props} ref={ref} />
</ListContext.Provider>
);
});
useOptionContextStabilizer
Hook 確保 context 值僅在選項的狀態更新時才會變更。
自訂
選取的值外觀
您可以透過將函式提供給 renderValue
屬性來自訂選取的值顯示之外觀。此函式傳回的元素將在 Select 的按鈕內呈現。
選項外觀
選項不必是純字串。您可以包含要呈現在 listbox 內部的自訂元素。