2022 第21週 實作筆記: MaterialUI theme 一鍵換皮
2022-05-29 10:55 MaterialUI React
總結
使用 React Context 來達成一鍵切換主題的效果

展示:https://tzynwang.github.io/mui-daisy-theme-demo-20220529/
原始碼:https://github.com/tzynwang/mui-components/tree/demo/20220529
色票組合:使用 daisyUI: Colors 中的 coffee 、 cupcake 與 retro
版本與環境
@mui/material: 5.8.1
@mui/styles: 5.8.0
daisyui: 2.15.1
筆記
React.createContext
- 透過
React.createContext建立ThemeContext物件,並value={{ themeName, setThemeName }} - 在元件
ThemeToggle中透過React.useContext(ThemeContext)取得context物件,即可在使用者選擇不同主題時更新ThemeKey
@Models/Theme
- 在建立 Theme 物件(
new Theme())時,根據THEME_KEYS載入對應的主題設定檔,並透過 MaterialUI 的createTheme建立MuiTheme物件
@Components/App
- 使用 useEffect 監聽目前的
themeName,並透過Theme.getTheme(themeName)取得對應的MuiTheme物件提供給 MaterialUI 的ThemeProvider
關於 deepMerge()
-
官方型別定義如右:
deepmerge<T>(target: T, source: unknown, options?: DeepmergeOptions): T -
原始碼如下,可得知
source的樣式設定會覆蓋掉target的內容,最終回傳被覆蓋後的target:function deepmerge( target, source, options = { clone: true, } ) { const output = options.clone ? (0, _extends2.default)({}, target) : target; if (isPlainObject(target) && isPlainObject(source)) { Object.keys(source).forEach((key) => { // Avoid prototype pollution if (key === '__proto__') { return; } if ( isPlainObject(source[key]) && key in target && isPlainObject(target[key]) ) { // Since `output` is a clone of `target` and we have narrowed `target` in this block we can cast to the same type. output[key] = deepmerge(target[key], source[key], options); } else { output[key] = source[key]; } }); } return output; }
備註
- 自定義的
MuiTheme需由開發者自行定義mode: light與mode: dark下的顏色樣式,切換自定義 MuiTheme 的palette.mode不會自動計算出對應的palette - 參考 MaterialUI 官方文件說明: If you have a custom palette, you need to make sure that you have the correct values based on the mode. The next section explain how to do this.