当前位置: 首页 > article >正文

nextjs+material UI实现换肤功能

一、搭建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 }}>
      <IconButton
        size="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;

三、重启运行

 


http://www.kler.cn/a/570576.html

相关文章:

  • 2继续NTS库学习(读取shapefile)
  • 【Kubernets】K8S亲和性配置相关说明
  • 【Linux】命名管道
  • python小游戏-坦克大战
  • yolo初体验
  • 【AI深度学习基础】Pandas完全指南入门篇:数据处理的瑞士军刀 (含完整代码)
  • 智慧农业中光谱相机对土壤成分的无损检测应用‌
  • 网络空间安全(7)攻防环境搭建
  • 初识C语言之操作符详解(下)
  • 服务器时间同步
  • spring boot + vue 搭建环境
  • 关于服务器cpu过高的问题排查
  • 物理竞赛中的线性代数
  • SELinux 安全加固
  • 【鸿蒙Next】鸿蒙与flutter使用自定义iconfont的ttf字体库对比总结
  • 基于GTID的主从复制
  • 静态时序分析:SDC约束命令set_clock_jitter详解
  • 学习笔记-DeepSeek在开源第四天发布DualPipe和EPLB两项技术
  • C#中泛型的协变和逆变
  • 关于常规模式下运行VScode无法正确执行“pwsh”问题