一、搭建nextjs开发环境
1、创建一个命名为nextjs-mui-theme的项目
pnpm dlx create-next-app@14.2.16 nextjs-mui-theme
注释:这是使用的是nextjs的14.2.16版本
2、安装material-ui依赖
pnpm add @mui/material @emotion/react @emotion/styled
material-ui官网
3、安装Roboto font和nextjs兼容mui所需的依赖
pnpm add @fontsource/roboto
pnpm add @mui/material-nextjs @emotion/cache
安装完毕后,在layout布局页面引入字体,以及引入这个依赖:
import '@fontsource/roboto/300.css';
import '@fontsource/roboto/400.css';
import '@fontsource/roboto/500.css';
import '@fontsource/roboto/700.css';
import { AppRouterCacheProvider } from '@mui/material-nextjs/v15-appRouter';
import type { Metadata } from 'next';
import './globals.css';export const metadata: Metadata = {title: 'Create Next App',description: 'Generated by create next app'
};export default function RootLayout({children
}: Readonly<{children: React.ReactNode;
}>) {return (<html lang="en" suppressContentEditableWarning><body>{/* 调用我们自己的css层,因此这选择关闭 */}<AppRouterCacheProvider>{children}</AppRouterCacheProvider></body></html>);
}
在 HTML 或 React 中,suppressContentEditableWarning
属性的作用是 抑制内容可编辑元素 (contentEditable
) 的警告。
4、安装material icon
pnpm add @mui/icons-material
然后在globals.css当中引入material icon的样式:
@import url(https://fonts.googleapis.com/icon?family=Material+Icons);
@tailwind base;
@tailwind components;
@tailwind utilities;* {box-sizing: border-box;padding: 0;margin: 0;
}
html,
body {max-width: 100vw;overflow-x: hidden;
}
.myBg {color: var(--mui-palette-common-background);
}@layer utilities {.text-balance {text-wrap: balance;}
}
注意@import url(https://fonts.googleapis.com/icon?family=Material+Icons);引入要放到tailwindcss上面,否则会爆出错误
二、自定义material主题
1、创建主题文件
在src目录下创建上下文context目录,在该目录下创建一个AppThemeContext.tsx文件,代码如下:
'use client';
import { createTheme, CssBaseline, responsiveFontSizes } from '@mui/material';
import { ThemeProvider } from '@mui/material/styles';
import type {} from '@mui/material/themeCssVarsAugmentation';
import { createContext, useContext, useMemo } from 'react';
export const AppThemeContext = createContext(null);const AppThemeProvider = ({children
}: Readonly<{children: React.ReactNode;
}>) => {const theme = useMemo(() => {return responsiveFontSizes(createTheme({// 使用CSS变量的有点,防止暗黑模式SS、闪烁cssVariables: {colorSchemeSelector: 'class',disableCssColorScheme: true},palette: {mode: 'light',primary: {main: 'rgb(10, 18, 42)',contrastText: 'rgb(255, 255, 255)'},secondary: {main: 'rgb(27, 59, 111)',contrastText: 'rgb(255, 255, 255)'}},// 在这里你可以定义不同的颜色方案colorSchemes: {// 这是亮色的配置设置light: {palette: {mode: 'light',primary: {main: 'rgb(10, 18, 42)'},secondary: {main: 'rgb(27, 59, 111)'}}},// 这是深色的配置设置dark: {palette: {mode: 'dark',primary: {main: 'rgb(10, 18, 42)'},secondary: {main: 'rgb(27, 59, 111)'}}}}}));}, []);return (<AppThemeContext.Provider value={null}>{/* defaultMode默认是system,可选项有system、light、dark ;disableTransitionOnChange禁用切换动画*/}<ThemeProvider defaultMode="dark" theme={theme} disableTransitionOnChange>{/*在所有设备上, 启用颜色方案 */}<CssBaseline enableColorScheme />{children}</ThemeProvider></AppThemeContext.Provider>);
};export const useAppThemeContext = () => useContext(AppThemeContext);
export default AppThemeProvider;
然后引入到layout布局组件当中:
import AppThemeProvider from '@/context/AppThemeContext';
import '@fontsource/roboto/300.css';
import '@fontsource/roboto/400.css';
import '@fontsource/roboto/500.css';
import '@fontsource/roboto/700.css';
import { AppRouterCacheProvider } from '@mui/material-nextjs/v15-appRouter';
import InitColorSchemeScript from '@mui/material/InitColorSchemeScript';
import type { Metadata } from 'next';
import './globals.css';export const metadata: Metadata = {title: 'Create Next App',description: 'Generated by create next app'
};export default function RootLayout({children
}: Readonly<{children: React.ReactNode;
}>) {return (<html lang="en" suppressContentEditableWarning><body>{/* 调用我们自己的css层,因此这选择关闭 */}<AppRouterCacheProvider options={{ enableCssLayer: false }}><AppThemeProvider><InitColorSchemeScript defaultMode="dark" attribute="class" />{children}</AppThemeProvider></AppRouterCacheProvider></body></html>);
}
2、创建切换主题按钮
在src下创建components文件夹,定一个ToggleModeColor.tsx组件:
'use client';
import DarkModeOutlinedIcon from '@mui/icons-material/DarkModeOutlined';
import LightModeOutlinedIcon from '@mui/icons-material/LightModeOutlined';
import { Box, IconButton } from '@mui/material';
import { useColorScheme } from '@mui/material/styles';
import { useCallback } from 'react';
const ToggleModeColor = () => {const { mode, setMode } = useColorScheme();const toggleDarkMode = useCallback(() => {if (mode) {const currMode = mode === 'light' ? 'dark' : 'light';setMode(currMode);}}, [mode, setMode]);return (<Box sx={{ flexGrow: 0, pr: 2 }}><IconButtonsize="large"aria-label="account of current user"aria-controls="menu-appbar"aria-haspopup="true"onClick={toggleDarkMode}color="inherit">{mode === 'dark' ? <DarkModeOutlinedIcon /> : <LightModeOutlinedIcon />}</IconButton></Box>);
};export default ToggleModeColor;
三、重启运行