自訂 MUI Base 元件
有多種方法可以自訂 MUI Base 元件,從套用自訂 CSS 規則到使用 Hook 建構完全自訂的元件。
使用 MUI Base,您可以自由決定要自訂元件的結構和樣式的程度。
為元件設定樣式
本節回顧幾種可用的自訂方法:套用自訂 CSS 規則、覆寫預設子元件插槽、自訂插槽 props,以及使用 Hook 建構完全自訂的元件。
該選擇哪個選項?
眾多的選項可能會讓人不知所措,尤其是當您是 MUI Base 的新手時。那麼,該如何決定使用哪個選項呢?
首先要做的決定是是否使用無樣式元件或 Hook。Hook 更適合用於建立可以進一步自訂的元件庫。例如,我們自己的 Joy UI 就是使用 MUI Base 的 Hook 實作的。Hook 也作為許多 Material UI 元件的基礎,並且該程式庫的未來版本將更廣泛地使用它們。
如果您不需要使您的元件庫可自訂(例如,透過公開 slotProps
),那麼無樣式元件可能是更好的選擇,因為它們更簡單。
在選擇無樣式元件之後,還有一個決定要做:如何為它們設定樣式。答案取決於專案中使用的樣式解決方案
純 CSS、Sass、Less
...或任何其他編譯為 CSS 的東西
您可以使用內建類別為元件設定樣式,或者指定您自己的類別並在樣式表中參考它們。
CSS Modules
當使用 CSS Modules 時,最簡單的方法是使用 slotProps
指定自訂類別,如下所示
import clsx from 'clsx';
import { Switch as BaseSwitch, SwitchOwnerState } from '@mui/base/Switch';
import classes from './styles.module.css';
export default function Switch(props) {
const slotProps = {
root: (ownerState: SwitchOwnerState) => ({
className: clsx(classes.root, {
[classes.checked]: ownerState.checked,
[classes.disabled]: ownerState.disabled,
}),
}),
thumb: { className: classes.thumb },
track: { className: classes.track },
input: { className: classes.input },
};
return <BaseSwitch {...props} slotProps={slotProps} />;
}
在此範例中,我們使用 clsx 實用工具來減少有條件地套用類別名稱所需的工作量。
Tailwind CSS
使用 slotProps
套用自訂樣式,使用 Tailwind CSS,如下所示
import { Switch as BaseSwitch, SwitchOwnerState } from '@mui/base/Switch';
export default function Switch(props) {
const slotProps = {
root: (ownerState: SwitchOwnerState) => ({
className: `inline-block w-8 h-5 rounded-full cursor-pointer relative ${
ownerState.checked ? 'bg-cyan-500' : 'bg-zinc-400'
}`,
}),
thumb: (ownerState: SwitchOwnerState) => ({
className: `bg-white block w-3.5 h-3.5 rounded-full relative top-[3px] ${
ownerState.checked ? 'left-[3px]' : 'left-[14px]'
}`,
}),
input: { className: 'absolute w-full h-full inset-0 opacity-0 z-10 m-0' },
};
return <BaseSwitch {...props} slotProps={slotProps} />;
}
請參閱我們的使用 Tailwind CSS 指南,以取得有關整合 MUI Base 和 Tailwind CSS 的更多資訊。
Styled components
如果您將 CSS-in-JS 解決方案與類似 styled-components 的 API(例如 MUI System 或 Emotion)一起使用,最好的方法是使用 slots
prop 提供樣式化的子元件,如下面的示範所示。
或者,您可以將整個無樣式元件包裝在 styled
實用工具中,並使用 CSS 類別來針對個別子元件
套用自訂 CSS 規則
如果您對元件的呈現 HTML 的預設結構感到滿意,則可以將自訂樣式套用到元件的類別。
每個元件都有自己的一組類別。有些類別是靜態的,也就是說它們始終存在於元件上。其他類別是有條件地套用的——例如 base--disabled
,它僅在元件被停用時存在。
每個元件的 API 文件都列出了元件使用的所有類別。此外,您可以匯入一個 [componentName]Classes
物件,該物件描述了給定元件使用的所有類別,如下面的示範所示
如果您不使用這些類別,您可以透過停用它們來清理 DOM。請參閱停用預設 CSS 類別以取得說明。
覆寫子元件插槽
如果您想變更元件的呈現 HTML 結構,可以使用 slots
和/或 component
prop 覆寫預設子元件(「插槽」)——請參閱 Base 用法頁面上的「共用 props」以取得更多詳細資訊。
以下示範使用 Switch 來展示如何透過將樣式套用到其三個子元件插槽來建立樣式化元件:root
、thumb
和 input
。
請注意,雖然此示範使用 MUI System 作為樣式解決方案,但您可以自由選擇任何替代方案。
您在 slots
prop 中傳遞的元件會從頂層元件(「擁有者」)接收 ownerState
prop。依照慣例,它包含傳遞給擁有者的所有 props,並與其呈現狀態合併。
例如
<Switch slots={{ thumb: MyCustomThumb }} data-foo="42" />
在這種情況下,MyCustomThumb
元件接收具有以下資料的 ownerState
物件
{
checked: boolean;
disabled: boolean;
focusVisible: boolean;
readOnly: boolean;
'data-foo': string;
}
您可以使用此物件來為您的元件設定樣式。
如果您需要使用 ownerState
將某些 props 傳播到第三方元件,則必須為此目的建立自訂包裝器。但是,如果您不需要 ownerState
而只想解決錯誤,則可以使用 prepareForSlot
實用工具
自訂插槽 props
使用 slotProps
prop 自訂內部元件 props。最常見的用例是設定類別名稱,但您可以設定任何 prop,包括事件處理常式。
以下範例示範如何將自訂類別新增到 Switch 的兩個插槽
function Switch(props: SwitchProps) {
const slotProps: SwitchProps['slotProps'] = {
thumb: {
className: 'my-thumb',
},
track: {
className: 'my-track',
},
};
return <Switch {...props} slotProps={slotProps} />;
}
switch:thumb
和 switch:class
是無條件新增的——它們將始終存在於 Switch 元件上。
您可能需要僅在元件處於特定狀態時才套用類別。一個很好的例子是根據 Switch 的 checked 狀態將 on
和 off
類別新增到 Switch,如下面的示範所示
在這裡,根插槽接收的是回呼函式,而不是具有 props 的物件。它唯一的參數是 ownerState
,它是一個描述「擁有者元件」(在本例中為 Switch)狀態的物件。ownerState
保留擁有者元件的所有 props(在適用情況下套用預設值),並透過元件的內部狀態進行擴充。就 Select 而言,額外資訊包括 checked
、disabled
、focusVisible
和 readOnly
布林值欄位。
使用 Hook 建立自訂元件
如果您需要完全控制元件的呈現 HTML 結構,可以使用 Hook 建構它。
Hook 讓您可以存取元件使用的邏輯,但沒有任何預設結構。請參閱 Base 用法頁面上的「元件與 Hook」以取得更多詳細資訊。
Hook 傳回元件的目前狀態(例如 checked
、disabled
、open
等),並提供傳回您可以套用到完全自訂元件的 props 的函式。
就 Switch 而言,該元件附帶 useSwitch
Hook,它在沒有任何結構的情況下為您提供所有功能。
它傳回以下物件
{
checked: Readonly<boolean>;
disabled: Readonly<boolean>;
readOnly: Readonly<boolean>;
focusVisible: Readonly<boolean>;
getInputProps: (otherProps?: object) => SwitchInputProps;
}
checked
、disabled
、readOnly
和 focusVisible
欄位代表 Switch 的狀態。使用它們將樣式套用到您的 HTML 元素。
getInputProps
函式可用於取得要放置在 HTML <input>
上的 props,以使 Switch 具有無障礙功能。
停用預設 CSS 類別
如果您不需要元件上的內建類別,您可以停用它們。這將清理 DOM,並且如果您套用自己的類別或使用 CSS-in-JS 解決方案為元件設定樣式,則這可能特別有用。若要執行此操作,請將您的元件包裝在 ClassNameConfigurator 元件中(從 @mui/base/utils
匯入)
<ClassNameConfigurator disableDefaultClasses>
<Button>I'm classless!</Button>
</ClassNameConfigurator>
檢查以下示範中的元素以查看差異