跳到主要內容
+

選擇器

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 表單提交到伺服器。

按下 Enter 鍵開始編輯

您可以自訂這個隱藏輸入框的值—詳情請參閱「物件值」章節。

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,並使用轉場效果元件 (CssTransitionCssAnimation 或自訂建置的元件) 包裝它。

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 不支援slot 屬性,但它們支援自訂屬性

以下範例顯示使用 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 的按鈕內呈現。

按下 Enter 鍵開始編輯

選項外觀

選項不必是純字串。您可以包含要呈現在 listbox 內部的自訂元素。

按下 Enter 鍵開始編輯