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

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;

三、重启运行

 

相关文章:

  • 数据集/API 笔记:湿球黑球温度(WBGT)观测数据
  • Linux cat 命令
  • JavaWeb-idea配置smart tomcat
  • Java设计模式 —— 【行为型模式】迭代器模式(Iterator Pattern)详解
  • 我的ChatGPT怎么登不上?
  • CentOS7安装 FFmpeg
  • Self-Pro: A Self-Prompt and Tuning Framework for Graph Neural Networks
  • Spring Boot 监听器(Listeners)详细教程
  • 2024华为OD机试真题-热点网站统计(C++)-E卷-100分
  • AVM 环视拼接 鱼眼相机
  • 离散傅里叶变换(Discrete Fourier Transform, DFT)及其在图像处理中的应用
  • 动态表头报表的绘制与导出
  • 内网穿透的应用-企业级远程办公方案:NAS部署网页版Linux,HTTPS加密访问全配置
  • Ubuntu 创建新用户及设置权限
  • SSH远程登录并执行命令
  • 工程化与框架系列(10)--微前端架构
  • springboot使用redis
  • 前端请求乱序问题分析与AbortController、async/await、Promise.all等解决方案
  • 技术速递|增强 Razor 生产力的新功能!
  • Redis数据结构详解
  • 泽连斯基:乌克兰已做好与俄罗斯举行会谈的准备
  • 马鞍山市原常务副市长黄化锋一审获刑11年,涉案金额三千余万元
  • 面对非专业人士,科学家该如何提供建议
  • 工行回应两售出金条发现疑似杂质:情况不属实,疑似杂质应为金条售出后的外部附着物
  • 心相印回应官方旗舰店客服辱骂消费者:正排查
  • 习近平在俄罗斯媒体发表署名文章