【React】Ant Design自定义主题风格及主题切换

news/2024/5/17 18:09:41

Ant Design 的自定义主题,对于刚入手的时候感觉真是一脸蒙圈,那今天给它梳理倒腾下;

在这里插入图片描述

1、自定义主题要点

整体样式变化,主要两个部分:

1.1、Design Token

https://ant.design/docs/react/customize-theme-cn#theme

官方介绍一大堆,咱们粗暴点就当作key=>value配置内容来看和理解!
大体分为四块配置项:

分类涉及配置项
通用/基本样式token可查阅SeedToken、MapToken、AliasToken
组件样式components查阅各个组件最底下的主题变量(Design Token)内容
样式算法algorithm这块其实就算UI库内部自动帮你换算不同“等级”颜色color值
扩展配置inherit、cssVar、hashed这块应该很少会去改它,做主题切换的时候建议cssVar开启

1.2、全局配置 ConfigProvider 组件

https://ant.design/components/config-provider-cn

import React from 'react';
import { ConfigProvider } from 'antd';// ...
const Demo: React.FC = () => (<ConfigProvider componentSize={"middle"}>// 界面组件</ConfigProvider>
);export default Demo;

这块涉及到主题样式的主要是componentSize配置项和组件配置

2、实战

以下做个实验性案例,不要纠结细节哈!

2.1、实验环境

  • next: 14.1.0
  • react:^18
  • antd:^5.14.1
√ Would you like to use TypeScript? ... Yes
√ Would you like to use ESLint? ... No
√ Would you like to use Tailwind CSS? ... No
√ Would you like to use `src/` directory? ... No
√ Would you like to use App Router? (recommended) ... Yes
√ Would you like to customize the default import alias (@/*)? ... Yes
√ What import alias would you like configured? ... @/*

2.2、目录结构

| - app|- page.tsx
|- theme|- default|- index.ts|- custom|- index.ts|- index.ts|- themeCenter.ts

2.3、相关文件编写

2.3.1、page.tsx

主要方便实验展示

"use client";import React, { useState } from "react";
import {SearchOutlined,AppstoreOutlined,MailOutlined,SettingOutlined,
} from "@ant-design/icons";
import { Button, Flex, Tooltip, Menu, Pagination, Divider } from "antd";import ThemeComponents from "@/theme";const items: any = [{label: "Navigation One",key: "mail",icon: <MailOutlined />,},
];const App: React.FC = () => {const [theme, setTheme] = useState("default");return (<><Flex gap="small"><Button type="primary" onClick={() => setTheme("default")}>主题1</Button><Button type="primary" onClick={() => setTheme("custom")}>主题2</Button></Flex><Divider /><ThemeComponents theme={theme} dark={'light'}><Flex gap="small" vertical><Flex wrap="wrap" gap="small"><Button type="primary" shape="circle">A</Button><Button type="primary" icon={<SearchOutlined />}>Search</Button><Tooltip title="search"><Button shape="circle" icon={<SearchOutlined />} /></Tooltip><Button icon={<SearchOutlined />}>Search</Button></Flex><Menu mode="horizontal" items={items} selectedKeys={["mail"]} /><Pagination defaultCurrent={1} total={50} /></Flex></ThemeComponents></>);
};export default App;

2.3.1、ThemeComponents

// 这里仅演示主题切换,其他业务逻辑~~~自己探索哈!
import React, { useEffect, useState } from "react";
import { ConfigProvider } from "antd";
import { ThemeModeEnum } from "@/theme/themeCenter.d";
import DefaultTheme from "./default";
import CustomTheme from "./custom";type Props = {theme: string;dark?: boolean,children: React.ReactNode;
};const ThemeMap = {default: DefaultTheme,custom: CustomTheme,
};const ThemeComponents = ({ theme = "default", dark, children }: Props) => {theme = theme ? theme : "default";const [themeCenter, setThemeCenter] = useState(new ThemeMap[theme]());const [darkTheme, setDarkTheme] = useState(dark);useEffect(() => {console.log("theme:", theme);setThemeCenter(new ThemeMap[theme]());}, [theme]);useEffect(() => {console.log("darkTheme:", dark);if(themeCenter){themeCenter.ThemeMode = dark;setDarkTheme(dark);}}, [dark]);return (<ConfigProvider {...themeCenter?.ThemeConfigProvider}>{children}</ConfigProvider>);
};export default ThemeComponents;

2.3.1、Theme管理

这部分主要涉及两个部分:基础主题类继承主题类

继承主题类
这部分主要用于不同主题样式的具体化配置
按主题目录区分,方便主题做其他更复杂的扩展预留空间

// 案例file: theme/default/index.ts
import ThemeCenter from "../themeCenter"class ThemeConfiguration extends ThemeCenter
{// 这是父级ThemeCenter下放的初始化方法,主题初始化在这里进行// 除_initThemeConfig方法外,其他的可自行定义protected _initThemeConfig(){ // 设置主题色this.ThemeColor = '#FF5C00';// 设置基础主题样式Tokenthis.setThemeAllToken({fontSize: 14,colorLink: '#1890ff',}, 'token')// 设置组件样式Tokenthis.LayoutComponentsToken();this.MenuComponentsToken();// ConfigProvider组件默认配置this.setThemeConfigProvider({componentSize: 'small'})}protected LayoutComponentsToken(){this.setThemeComponentsToken('Layout',{headerBg: '#fff',headerColor: '#333',headerHeight: 35,headerPadding: '0 16px 0 0',lightSiderBg: 'transparent',siderBg: '#fff',bodyBg: 'transparent',// footerBg: '#f2f3f5',// footerPadding: '24px 0'});}protected MenuComponentsToken(){// @link https://ant.design/components/menu-cn#%E4%B8%BB%E9%A2%98%E5%8F%98%E9%87%8Fdesign-tokenthis.setThemeComponentsToken('Menu',{collapsedWidth: 46// itemBg: "rgba(255,255,255, .85)",// darkItemBg: 'var(--ant-layout-sider-bg)',// darkItemColor: 'rgba(0,0,0, .65)',// darkItemDisabledColor: 'rgba(0,0,0, .25)',// darkItemHoverBg: 'rgba(255,92,0, .65)',// darkItemHoverColor: '#fff',// darkPopupBg: '#181818',// darkSubMenuItemBg: 'var(--ant-layout-sider-bg)',})}
}export default ThemeConfiguration;

基础主题类

// file: /theme/themeCenter.tsimport type {ThemeConfig,ThemeComponentsConfig,ThemeConfigProviderProps
} from "./themeCenter.d"
import { ThemeModeEnum } from "./themeCenter.d"
import {theme} from "antd";class ThemeCenter {private themeName = "default";private themeColor:string = '#FF5C00';private themeMode:ThemeModeEnum = ThemeModeEnum.AUTO;/*** 明暗算法配置*  @var {object} _algorithm*/private _algorithm = {light: theme.defaultAlgorithm,dark: theme.darkAlgorithm}private _lightAlgorithm = this._algorithm['light'];private _darkAlgorithm = this._algorithm['dark'];/*** 自定义主题配置* @link https://ant.design/docs/react/customize-theme-cn#theme* @var {ThemeConfig} _customThemeToken*/private _customThemeToken:ThemeConfig = {token: {},// 继承上层 ConfigProvider 中配置的主题inherit: true,algorithm: this._algorithm['light'],components: {},// 开启 CSS 变量,参考使用 CSS 变量// @link https://ant.design/docs/react/css-variables-cn#apicssVar: {prefix: 'bogoo',key: 'theme',},// 组件 class Hash 值hashed: true,}/*** 自定义ConfigProvider组件配置** @var {ThemeConfigProviderProps} _customConfigProvider*/private _customConfigProvider:ThemeConfigProviderProps = {componentSize: undefined,theme: this._customThemeToken}constructor() {this._initThemeConfig();}protected _initThemeConfig(){}/**获取主题名称*/public get ThemeName(){return this.themeName;}/**获取当前主题色*/public get ThemeColor(){return this.themeColor;}public set ThemeColor(color: string){this.themeColor = color;this.setThemeAllToken({colorPrimary: color}, 'token')}/**获取明暗色系名称*/public get ThemeMode(){return this.themeMode;}/**设置明暗主题色配置*/public set ThemeMode(mode: ThemeModeEnum){this.themeMode = mode;let _algorithm: any = this._lightAlgorithm;if (mode === ThemeModeEnum.AUTO) {// _algorithm = this._darkAlgorithm;}else{_algorithm = mode===ThemeModeEnum.LIGHT ? this._lightAlgorithm : this._darkAlgorithm;}this.setThemeAllToken({algorithm: _algorithm});}/**主题Token配置*/public get ThemeToken(){return this._customThemeToken;}/*** 设置主题Token配置** @param {ThemeConfig|ThemeComponentsConfig} token 全局主题token或组件token* @param {'token'|'algorithm'|'components'} field 可选,若指定配置名称,则仅更新对应配置** @return {ThemeConfig}*/public setThemeAllToken(token: ThemeConfig|ThemeComponentsConfig,field?:'token'|'algorithm'|'components'){let _token:any = {};let _updateToken = token;if (field){if (!['token','algorithm','components'].includes(field))return this._customThemeToken;if (_updateToken instanceof Array){// @ts-ignore_token[field] = this._customThemeToken[field].concat(_updateToken)}else if(typeof _updateToken === 'object'){_token[field] = Object.assign({}, this._customThemeToken[field]||{}, _updateToken)}else{_token[field] = _updateToken}}else{_token = _updateToken;}console.log('_token:', _token)Object.assign(this._customThemeToken, _token);return this._customThemeToken;}/*** 组件主题Token配置** @param {string} componentsName 组件名称(首字母大小)* @param {ThemeComponentsConfig} token 主题样式配置** @return {void}*/public setThemeComponentsToken(componentsName:string, token: ThemeComponentsConfig){this.setThemeAllToken({// @ts-ignore[componentsName]: Object.assign({} ,this._customThemeToken?.components[componentsName]||undefined, token)}, 'components')}/**ConfigProvider组件配置*/public get ThemeConfigProvider(){return this._customConfigProvider;}public setThemeConfigProvider(config:ThemeConfigProviderProps){Object.assign(this._customConfigProvider, config);}
}export default ThemeCenter;

补充

  • themeCenter.d.ts
import type {ThemeConfig as AntdThemeConfig,ComponentsConfig as AntdComponentsConfig,
} from "antd/es/config-provider/context";
import type {SizeType} from "antd/es/config-provider/SizeContext";
import type {ReactNode} from "react";export enum ThemeModeEnum {AUTO = 'auto',DARK = 'dark',LIGHT = 'light'
}export interface ThemeConfigProviderProps {componentSize?: SizeType;theme?:AntdThemeConfig;
}export interface ThemeConfig extends AntdThemeConfig {}
export interface ThemeComponentsConfig extends AntdComponentsConfig {}

没啦!学废了嘛??!!!


http://www.mrgr.cn/p/11354562

相关文章

MySQL基础-----约束详解

目录 一. 概述: 二.约束演示&#xff1a; 三.外键约束&#xff1a; 3.1介绍&#xff1a; 3.2外键约束语法&#xff1a; 3.3删除&#xff0c;更新行为&#xff1a; 一. 概述: &#x1f9d0;&#x1f9d0;概念&#xff1a;约束是作用于表中字段上的规则&#xff0c;用于限制…

LCD显示器 --- 8080接口 和 RGB接口 的区别

主要介绍LCD显示的基本原理,涉及像素、分辨率、颜色模型、RGB888等格式、Framebuffer、8080接口、RGB接口。 1.LCD显示出图片的基本原理 LCD作为显示器,它的显示原理和图片是一样的。 图片可以看作由一个一个点(即像素pixel)组成。每行有xres个像素,有yres行,则这个图片的分…

Vue 3 项目构建与效率提升:vite-plugin-vue-setup-extend 插件应用指南

一、Vue3项目创建 前提是已安装Node.js&#xff08;点击跳转Node官网&#xff09; npm create vuelatest这一指令将会安装并执行 create-vue&#xff0c;它是 Vue 官方的项目脚手架工具。你将会看到一些诸如 TypeScript 和测试支持之类的可选功能提示&#xff1a; ✔ Projec…

Ubuntu 22.04 解决和 Windows 共享蓝牙设备的问题

我有一个 Airpods,连接到 WIndows 可以正常工作,但连接到 ubuntu 后会无法连接,只能删除设备选择重联,但是这又会导致 Windows 不能连接到耳机,只能也删除重新连接,费神费力。 要解决此问题,仍有两办法,让 Windows 将就 Linux,或者 Linux 将就 Windows,由于折腾注册表…

【STM32+HAL库】---- 驱动MAX30102心率血氧传感器

硬件开发板:STM32F407VET6 软件平台:cubemax+keil+VScode1 MAX30102心率血氧传感器工作原理 MAX30102传感器是一种集成了红外光源、光电检测器和信号处理电路的高度集成传感器,主要用于心率和血氧饱和度的测量。以下是MAX30102传感器的主要特点和工作原理:红外光源:MAX301…

OO第一次博客作业

OO第一次博客作业 目录1.前言 2.设计与分析 3.采坑心得 4.改进建议 5.总结 1.前言 正则表达式是java语言中一种非常重要的语言,他的重要性主要体现在以下方面: 1.高效的文本处理:正则表达式提供了一种高效的方式来处理文本数据。它可以快速地进行字符串的搜索、匹配、替换和…

【机器学习】数据变换---小波变换特征提取及应用案列介绍

引言 在机器学习领域&#xff0c;数据变换是一种常见且重要的预处理步骤。通过对原始数据进行变换&#xff0c;我们可以提取出更有意义的特征&#xff0c;提高模型的性能。在众多数据变换方法中&#xff0c;小波变换是一种非常有效的方法&#xff0c;尤其适用于处理非平稳信号和…

JVM——面试

https://juejin.cn/post/6998527815964426271 https://juejin.cn/post/7101120209540349959垃圾回收器 Serial(新生代)+ Serial Old(老年代) 特点:单线程垃圾回收器,垃圾回收过程中需要 STW,适用于运行在 Client 模式下的虚拟机; 新生代标记复制算法,老年代标记整理算法…

内存分配器

内存分配器 文章目录 内存分配器项目介绍内存池介绍池化技术内存池内存池主要解决的问题malloc 实现定长内存分配器怎么控制定长通过系统调用申请空间定长内存分配器中应该包含哪些成员变量内存池如何管理释放的对象内存分配器如何为我们申请对象定长内存池整体代码性能对比 高…

2024.4.19

2024.4.19 【你知道的都是真相。只可惜那些并不是真相的全部。】 Friday 三月十一 谷雨<BGM = "谷雨--音阙诗听"> AC :Answer Coarse,粗劣的答案 ​ CE :Compile Easily,轻松通过 ​ PC :Perfect Compile 完美的编译 ​ WA :Wonderful Answer,好答案 ​ RE :Ru…

Ubuntu 22.04 安装 Nvidia 驱动最方便安全的方式

刚安装好的 Ubuntu 22.04 没有 N 卡驱动,输入 nvidia-smi,提示没有此程序并推荐到 apt 安装。 但是,使用 apt 安装 nvidia 驱动会有极大概率出现启动黑屏和闪屏问题。 不如进入开始菜单,找到“附加驱动”:此处展示了可用的 Nvidia 驱动,选择自己想要的版本安装,"te…

Mockito单元测试

文章目录 Mockito单元测试 为什么要使用Mock?导入依赖import导入包使用Mock模拟测试某个类中的某个方法是否可以成功执行使用Mock模拟某个类的方法&#xff0c;自己给这个方法返回我们指定的值使用Mock模拟某个方法调用后会抛出指定的异常使用Mock模拟测试某个类中的某个方法(…

浅述.Net中的Hash算法(顺带对称、非对称算法)

【写在前面】 对称加密算法(只有一个私钥&#xff0c;比如DES【不推荐】、AES)&#xff1b; 非对称加密算法&#xff08;公钥与私钥&#xff0c;比如RSA&#xff09;&#xff1b; Hash算法也称为散列函数算法&#xff0c;任意长度的数据都转换为固定长度的字符串&#xff08…

【opencv】示例-videocapture_starter.cpp 从视频文件、图像序列或连接到计算机的摄像头中捕获帧...

/** * file videocapture_starter.cpp * brief 一个使用OpenCV的VideoCapture与捕获设备&#xff0c;视频文件或图像序列的入门示例 * 就像CV_PI一样简单&#xff0c;对吧&#xff1f; * * 创建于: 2010年11月23日 * 作者: Ethan Rublee * * 修改于: 2013年4月17日 * …

EasyExcel追加写入数据,分批查询多次写入场景下,注意使用方式【OOM警告】

使用.withTemplate(file) 将临时数据文件和真实数据文件合并的方式&#xff0c;在生产环境大批量数据下&#xff0c;完全不可取&#xff0c;有很高的内存溢出风险 伪代码 public static void writeAppend(String fileName) {String filePath "tempDir".concat(Fil…

GDExtension的C++示例

GDExtension的C++示例 本文按照官方文档,进行c++的GDExtension​插件开发,主要进行文档进行复刻,同时对文档中未涉及步骤进行补充 什么是GDExtension 除了GDScript​和C#​这两种脚本语言外,Godot​引擎可以执行其他编程语言编写的代码。目前有两种方式实现:C++模块与GDEx…

再见,晚晚

一、 尽管多少有些预感,但听到消息的时候,泪水还是几近夺眶而出。 “祝愿晚晚能坚持自己的梦想” “ymgg我们等生日会给晚晚一起录制一个祝福吧” 却是一语成谶,只留一个在屏幕前迷茫的我。 其实我已经很久没有完整地看一次晚晚的单播了。 但是,当看到晚晚的告别动态的时候…

探索人工智能绘图的奇妙世界

探索人工智能绘图的奇妙世界 人工智能绘图的基本原理机器之美&#xff1a;AI绘图作品AI绘图对艺术创作的影响未来展望与挑战图书推荐&#x1f449;AI绘画教程&#xff1a;Midjourney使用方法与技巧从入门到精通内容简介获取方式&#x1f449;搜索之道&#xff1a;信息素养与终身…

实验1 原型设计————一款法律咨询及科普类app

一、实验题目:原型设计 二、实验目的:掌握产品原型设计方法和相应工具使用。 三、实验要求 (1)对比分析墨刀、Axure、Mockplus等原型设计工具的各自的适用领域及优缺点(至少3条)。 1.墨刀: 适用领域: 产品设计,项目管理,可以利用墨刀绘制流程图,明确项目流程和时间节…

这是一篇有颜色的文章。

三张图片都是一样的,但大小不一样。