MUI 筆記

非常好用。

基礎應用

這邊是比較偏 CSS 的應用,推薦可以把官方文件的 system 部分給看完,這邊只會列幾個我想特別記一下的。

sx 屬性

這應該是 MUI 裡面最重要的一個東西。

簡單來說只要是 MUI 的組件都可以用 sm 這個 props,他基本上就跟 style 的用途差不多,但重點有兩個:

  1. 他不是 inline-style(絕對別搞錯囉)
  2. 可以用 MUI 專屬的 utils 來寫樣式(當 tailwind 在寫 XD)

所以如果想畫一個簡單的方塊

basic-box

我可以這樣寫:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
export default function Color() {
return (
<div>
<Box
sx={{
width: 1 / 2, // 50%
color: 'white',
textAlign: 'center',
fontWeight: 'bold',
background: 'dodgerblue',
borderRadius: '4px',
py: 1, // 1 = 8px
px: 2 // 2 = 16px
}}
>
Box1
</Box>
</div>
)
}

因為 sx 很好用的關係,所以當你用了 MUI 以後通常會直接拿 <Box> 來取代 <div>

Spacing

MUI 預設的間距是 8px,所以只要跟間距有關的設定都會拿 8px 來當作基準,像是常見的 margin 跟 bottom 就會這樣寫:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
export default function Spacing() {
const boxStyle = (bg) => ({
width: 1 / 2,
color: 'white',
textAlign: 'center',
fontWeight: 'bold',
background: bg,
borderRadius: '4px',
py: 1, // 1 = 8px
px: 2, // 2 = 16px
mt: 2, // 16px
ml: 4
})

return (
<div style={{ margin: 50 }}>
<Box sx={boxStyle('dodgerblue')}>Box1</Box>
<Box sx={boxStyle('cadetblue')}>Box1</Box>
</div>
)
}

spacing

Shadow

這個是懶的時候很好用(雖然私心覺得 Tailwind 的 shadow 寫得更自然一些)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
export default function Shadow() {
const boxStyle = {
width: 1 / 2,
color: '#555',
textAlign: 'center',
background: 'white',
borderRadius: '4px',
boxShadow: 1, // shadow
py: 1,
px: 2,
m: 4
}

return (
<div style={{ margin: 50 }}>
<Box sx={boxStyle}>Box1</Box>
<Box sx={boxStyle}>Box1</Box>
</div>
)
}

shadow

breakpoint

透過 sx 設定的樣式都可以在指定「在哪個 breakpoint 下套用」的規則,像這樣:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
export default function BreakPoint() {
const boxStyle = {
width: {
xs: 1, // minWidth > 0px
sm: 1 / 2 // minWidth > 600px
},
color: 'white',
background: 'dodgerblue',
textAlign: 'center',
borderRadius: '4px',
py: 1,
px: 2,
mt: 2
}

return (
<div>
<Box sx={boxStyle}>Box1</Box>
<Box sx={boxStyle}>Box1</Box>
</div>
)
}

預設的斷點是:

  • xs: 0px
  • sm: 600px
  • md: 900px
  • lg: 1200px
  • xl: 1536px

這個做 RWD 必備,所以記得學起來。不懂的話可以到這邊 範例 來看,我就不貼圖了。

display

這個就是用來設定 blockinline-block 等等之類的東西,跟 style 的寫法大同小異,所以這邊想特別講的是 textOverflow 的用法,只要搭配 <Box> 來用就能很輕鬆的做出 … 的效果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
export default function TextOverflow() {
const boxStyle = {
width: 1,
color: 'white',
background: 'dodgerblue',
overflow: 'hidden', // required
whiteSpace: 'nowrap', // required
textAlign: 'center',
borderRadius: '4px',
textOverflow: 'ellipsis', // required
py: 1, // 1 = 8px
px: 2, // 2 = 16px
mt: 2
}

return (
<div>
<Box sx={boxStyle}>
Lorem Ipsum is simply dummy text Lorem Ipsum is simply dummy text Lorem Ipsum is simply
dummy text
</Box>
</div>
)
}

不懂的話一樣能能參考我寫的範例

Palette(調色盤)

簡單來說像 colorbgcolor 這兩個東西可以直接用指定的字串來存取 MUI 的基本配色,像這樣:

palette

寫法也很簡單:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
export default function Color(bg) {
const boxStyle = (bg) => ({
width: 1,
color: 'white',
bgcolor: bg,
overflow: 'hidden',
whiteSpace: 'nowrap',
textAlign: 'center',
borderRadius: '4px',
textOverflow: 'ellipsis',
py: 2,
mt: 2
})

return (
<div>
<Box sx={boxStyle('primary.main')}>primary</Box>
<Box sx={boxStyle('secondary.main')}>secondary</Box>
<Box sx={boxStyle('success.main')}>success</Box>
<Box sx={boxStyle('warning.main')}>warning</Box>
</div>
)
}

範例到 這邊 看。至於字體顏色的用法也差不多,想知道更多的話看 官方文件 比較快。

TextField

這個寫表單的時候會蠻常用到的,這邊想特別記的幾個 props 有幾個:

  • required
  • helperText
  • Error
  • InputProps (ReadOnly)
  • multiline

演示的部分可以參考這裡

ThemeProvider

想參考預設值的話可以到 官方文件 看。

如果你想要覆蓋 MUI 預設的一些樣式,像是「顏色」、「間距」、「字體」和「陰影」之類的設定的話,可以用 ThemeProvider 的方式來覆寫。

來看一個最簡單的例子,假設我想把 primary 色改掉,那我可以這樣寫:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { createTheme, ThemeProvider } from '@mui/material/styles'

const theme = createTheme({
palette: {
primary: {
main: '#8d69f1'
}
}
})

ReactDOM.render(
<React.StrictMode>
<ThemeProvider theme={theme}>
<App />
</ThemeProvider>
</React.StrictMode>,
document.getElementById('root')
)

他背後是用 Context 來實作的,所以這例子的底下所有用到 primary 色的組件都會變成我寫的顏色。

如果我不想要他的 scope 那麼大,那就把 ThemeProvider 放在對應的組件上就好,像這樣:

1
2
3
4
5
6
7
8
9
10
export default function BasicButtons() {
return (
<Stack spacing={2} direction='row'>
<ThemeProvider theme={theme}>
<Button variant='contained'>Contained</Button>
</ThemeProvider>
<Button variant='contained'>Contained</Button>
</Stack>
)
}

theme-provider

useTheme 的用法

有時候你可能想寫一些 inline-style,但你想直接拿 MUI 寫好的樣式來用,這時候你就可以用 useTheme 來把對應的值取出來。

例如根據不同長度的文字我想套用不同的顏色:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import { useTheme } from '@mui/material/styles'
import { Typography } from '@mui/material'

export default function BasicButtons() {
// 透過他我就能存取所有 MUI 的樣式設定
const theme = useTheme()
const title1 = 'short Text'
const title2 = 'I an long short Text'

const getTypeStyle = (text, theme) => {
return {
color: text.length < 15 ? theme.palette.primary.main : theme.palette.secondary.main
}
}

// spacing(1) = 8px
return (
<div style={{ margin: theme.spacing(4) }}>
<Typography style={getTypeStyle(title1, theme)} variant='h6' component='div' gutterBottom>
{title1}
</Typography>
<Typography style={getTypeStyle(title2, theme)} variant='h6' component='div' gutterBottom>
{title2}
</Typography>
</div>
)
}

use-theme

可以直接當作 utility 來用,我覺得還蠻方便的。

關於 Selectbox 的一個小雷點

這邊只是記錄一下當初覺得很雷的 bug。

我原本預期結果是這樣子:

select-solution

但出來的結果是這樣子:

select-problem

就是 label 的部分總會超出 border 的線條,當初找了蠻久才找到解法

簡單來說 border 會隨著 <Select>label 來做調整,所以你一定要讓它的值跟顯示的 <InputLabel> 的內容是一樣的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<FormControl>
<InputLabel>Project Detail</InputLabel>
<Select
label='Project Detail' // 這個要跟上面的 <InputLabel> 對應
multiple
value={personName}
onChange={(e) => setPersonName(e.target.value)}
renderValue={(selected) => {
return (
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 1 }}>
{selected.map((value) => (
<Chip variant='outlined' key={value} label={value} />
))}
</Box>
)
}}
>
{names.map((name) => (
<MenuItem key={name} value={name}>
{name}
</MenuItem>
))}
</Select>
</FormControl>

客製化 CSS

sx 屬性

這是最簡單也是最推薦的作法,就是用 sx 屬性來改:

1
2
3
4
5
6
7
8
9
10
11
export default function SxProp() {
return (
<Slider
defaultValue={30}
sx={{
width: 300,
color: 'success.main'
}}
/>
)
}

custmize-property

可以看到這邊寫的樣式會出現在 .css-121j95d-MuiSlider-root 中。如果要用純 CSS 來做的話就無法了,因為 class 中有 hash 值。

在 sx 中使用 selector

一個元件通常是由多個 part 來組成的,像上面的 Slider 中就包含了 railtrackthumb 這幾個部位:

selectors

這邊順便介紹一下 MUI 的命名規則是 [hash]-Mui[元件名稱]-[元件中的其他插槽]

你可能會想說有 hash 值的話要怎麼寫?不過不用擔心,透過 sx 你只需要寫成 & .MuiSlider-[插槽名稱] 就可以了,不用擔心 hash 值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
export default function SxProp() {
return (
<Slider
defaultValue={30}
sx={{
width: 300,
color: 'success.main',
// 把按鈕的部分改成方形
'& .MuiSlider-thumb': {
borderRadius: 1
}
}}
/>
)
}

所以當你碰到「要改的部分是元件的插槽」時,就用這種方式來修改就行了。

Firbase-設定 Rules Firebase-V8 與 V9 的超級比一比
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×