如何扩展Material UI内置暗黑模式配色,实现自定义色值自动切换?
实现方案
该需求完全可以实现,无需修改MUI源码,仅通过应用层的主题配置即可达成。核心思路是:在创建主题实例时,根据当前传入的palette.mode值,动态将对应模式下的自定义色值挂载到调色板对象上。
步骤1:定义自定义色的明暗配置
先统一维护所有自定义色的亮/暗模式两套色值:
const customColorConfigs = { // 可添加任意数量自定义色 myColor: { light: '#1976d2', // 亮模式生效色值 dark: '#90caf9' // 暗模式生效色值 }, accentColor: { light: '#d32f2f', dark: '#ef9a9a' } }
步骤2:封装动态主题创建函数
包装MUI的createTheme方法,根据传入的模式自动匹配自定义色值:
import { createTheme } from '@mui/material/styles' export const getAppTheme = (mode) => { return createTheme({ palette: { mode, // 批量注入自定义色,无需逐个手动编写判断逻辑 ...Object.fromEntries( Object.entries(customColorConfigs).map(([colorName, colorValues]) => [ colorName, colorValues[mode] ]) ) } }) }
步骤3:全局主题Provider配置
在Next.js的入口文件_app.js中管理模式状态,动态生成主题:
import { useState, useMemo } from 'react' import { ThemeProvider } from '@mui/material/styles' import CssBaseline from '@mui/material/CssBaseline' import { getAppTheme } from './theme' export default function App({ Component, pageProps }) { // 管理当前明暗模式,可根据需求对接系统偏好、本地存储等 const [themeMode, setThemeMode] = useState('light') // 切换模式的方法可根据需求传递给全局任意组件调用 const toggleThemeMode = () => { setThemeMode(prev => prev === 'light' ? 'dark' : 'light') } // 缓存主题实例避免不必要重渲染 const theme = useMemo(() => getAppTheme(themeMode), [themeMode]) return ( <ThemeProvider theme={theme}> {/* CssBaseline会自动同步模式对应的全局背景、文字色 */} <CssBaseline /> <Component {...pageProps} toggleThemeMode={toggleThemeMode} /> </ThemeProvider> ) }
步骤4:组件内直接使用
之后就可以按照你期望的方式调用自定义色,色值会随模式自动切换:
import { Box } from '@mui/material' const DemoComponent = () => { return ( <Box sx={{ color: theme => theme.palette.myColor, borderColor: theme => theme.palette.accentColor }} > 测试内容 </Box> ) }
可选:TypeScript类型扩展
如果使用TypeScript,需要扩展MUI的Palette类型避免类型报错,在项目根目录新建mui.d.ts:
declare module '@mui/material/styles' { interface Palette { myColor: string accentColor: string } interface PaletteOptions { myColor?: string accentColor?: string } }
进阶:支持多阶自定义色
如果你希望自定义色和内置的primary/secondary一样支持main/light/dark/contrastText等多阶属性,只需要调整配置结构即可:
const customColorConfigs = { myColor: { light: { main: '#1976d2', light: '#42a5f5', dark: '#1565c0', contrastText: '#fff' }, dark: { main: '#90caf9', light: '#e3f2fd', dark: '#42a5f5', contrastText: '#000' } } }
使用时可以直接调用theme.palette.myColor.main,和内置色的用法完全一致。
内容的提问来源于stack exchange,提问作者paws
相关产品推荐
相关产品推荐

