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

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.mzph.cn/bicheng/783.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024信友队智灵班春季 Test1 总结

4月模考 死亡回放 模考时间线 1:30 比赛开始&#xff0c;读 T1 宇宙爆炸 的题1:50 自己手模了几组样例&#xff0c;得出了一个错误结论&#xff0c;打出了第一版错误代码&#xff0c;然后上交&#xff08; Wrong Answer 20 \color{red}\text{Wrong\ Answer\ 20} Wrong Answer …

【Vue 异步更新和 $nextTick】

文章目录 异步更新机制$nextTick 方法 异步更新机制以及 $nextTick 方法都与 Vue 的响应式系统密切相关&#xff0c;对于开发高效、流畅的应用至关重要。 异步更新机制 Vue 的数据更新是异步执行的。修改 Vue 实例的数据时&#xff0c;Vue 并不会立即更新 DOM。它将数据变更放…

每日一题(PTAL2-008):最长对称子串--分类讨论+遍历

最长对称子串的长度有可能是奇数也有可能是偶数&#xff0c;因此在遍历时要同时考虑这两种情况。 #include<bits/stdc.h> using namespace std;int main() {string s;getline(cin,s);int n s.size();int res 0; // 初始化为0&#xff0c;因为空字符串也是对称的for (i…

VMware最新下载安装

1、打开浏览器 搜索VMware官网&#xff0c;点进去。如图&#xff1a; 这里有两种下载方法&#xff0c;便洁就是我这种&#xff0c;还有一种就是注册账号之后下载就完全没有必要了&#xff0c;而且基本注册不了&#xff0c;不太好注册。 2、选择"产品"第二个选项 …

Oracle数据库从入门到精通系列之二十:Linux上使用容器数据库(CDB)方式部署Oracle数据库19c详细步骤

@TOC 一、Oracle 数据库部署类型 Oracle数据库支持以下部署类型: 容器数据库(CDB) 可以包含多个可插入数据库 (PDB) 的数据库。数据库客户端连接到每个 PDB,就好像它是标准的非 CDB 数据库一样。非容器数据库(非CDB) 标准Oracle数据库,不支持创建可插拔数据库。二、安…

OPTEE RUST支持构建并运行支持RUST的CA和TA

目录 一、RUST环境及代码准备 二、RUST构建演示 三、RUST运行演示 RUST语言,由于其更安全的编程语言特性,OPTEE作为可信执行环境的开源实现也增加了对RUST的支持。那么如何构建并运行支持RUST的CA和TA呢,本博客来探讨并进行qemu环境的实际演示。 一、RUST环境及代码准备…

从容器到协调:掌握Docker和Docker Compose的艺术

Docker 是一个开源的应用容器引擎&#xff0c;允许开发者打包他们的应用以及应用的依赖包到一个可移植的容器中&#xff0c;然后发布到任何流行的 Linux 机器上&#xff0c;也可以实现虚拟化。容器是完全使用沙箱机制&#xff0c;相互之间不会有任何接口&#xff08;类似 iPhon…

简单易学版 易操作版 man永久汉化 和help永久汉化 linux中

help 汉化 1 查看当前语言 echo $LANG locale 2 查看是否存在中文语言包 locale -a | grep zh_CN 3 没有就安装 yum install kde-l10n-Chinese 4 永久修改 vim /etc/locale.conf LANG"zh_CN.UTF-8" 重启后生效 或者 localectl set-l…

leetcode热题100.杨辉三角(动态规划入门)

Problem: 118. 杨辉三角 文章目录 题目思路复杂度Code 题目 给定一个非负整数 numRows&#xff0c;生成「杨辉三角」的前 numRows 行。 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 示例 1: 输入: numRows 5 输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,…

98.验证二叉搜索树

给你一个二叉树的根节点 root &#xff0c;判断其是否是一个有效的二叉搜索树。 有效 二叉搜索树定义如下&#xff1a; 节点的左 子树 只包含 小于 当前节点的数。节点的右子树只包含 大于 当前节点的数。所有左子树和右子树自身必须也是二叉搜索树。 方法一&#xff1a;中序…

Go语言并发控制

channel // cancelFn 数据通道关闭通知退出 func cancelFn(dataChan chan int) {for {select {case val, ok : <-dataChan:// 关闭data通道时&#xff0c;通知退出// 一个可选是判断data指定值时退出if !ok {fmt.Printf("Channel closed &#xff01;&#xff01;&…

OPEN CV 实现车辆统计

#加载视频 import cv2 import numpy as np cap cv2.VideoCapture(car.mp4) #去除背景 mog cv2.bgsegm.createBackgroundSubtractorMOG() kernel cv2.getStructuringElement(cv2.MORPH_RECT,(7,7)) min_w90 min_h90 line_hig400 #偏移量 offset2 cars[] carno0 #计算外矩形的中…

5. Django 探究CBV视图

5. 探究CBV视图 Web开发是一项无聊而且单调的工作, 特别是在视图功能编写方面更为显著. 为了减少这种痛苦, Django植入了视图类这一功能, 该功能封装了视图开发常用的代码, 无须编写大量代码即可快速完成数据视图的开发, 这种以类的形式实现响应与请求处理称为CBV(Class Base…

使用阿里云试用Elasticsearch学习:sentence-transformers 包使用

环境&#xff1a;centos8&#xff0c;windows坑太多。 一、检查linux环境openssl哪个版本&#xff08;如果是OpenSSL 1.1.1k 直接跳过&#xff09; [roothecs-334217 python39]# openssl version OpenSSL 1.0.2k-fips 26 Jan 2017原因后续会出麻烦&#xff0c;遇到这种情况最…

16.C++常用的算法_算数生成算法

文章目录 遍历算法1. accumulate()代码工程运行结果 2. fill()代码工程运行结果 遍历算法 1. accumulate() 代码工程 第三个参数为累加的起始值&#xff0c;如果没有特殊需求写0即可; 需要注意包含头文件#include<numeric>#define _CRT_SECURE_NO_WARNINGS #include&l…

为什么说创建一个index.html 文件 来作为javascript 一个 host

JavaScript代码运行环境的系统或平台&#xff0c;JavaScript代码需要一个“宿主环境”&#xff08;host environment&#xff09;来执行&#xff0c;这个环境提供了必需的资源、API和执行机制。 index.html 作为javaScript宿主环境的原因 说到使用一个 index.html 文件作为Ja…

【C语言】Dijkstra算法详解

一、引言二、Dijkstra算法原理三、Dijkstra算法的C语言实现四、Dijkstra算法的应用场景五、总结 一、引言 Dijkstra算法是一种著名的图论算法&#xff0c;用于解决单源最短路径问题。它是由荷兰计算机科学家Edsger W. Dijkstra在1956年提出的。本文将详细介绍Dijkstra算法的原理…

锂电池充放电管理-单片机通用模版

锂电池充放电管理-单片机通用模版 一、锂电池充放电检测的原理二、power.c的实现三、power.h的实现四、锂电池检测和充电电路一、锂电池充放电检测的原理 ①两节锂电池通过电阻分压检测ADC,再根据电压划分电量等级;②充电使用的是锂电池充电IC方案,可通过硬件电阻参数调节充…

代码随想录:二叉树11-12

目录 222.完全二叉树的节点个数 题目 代码&#xff08;层序迭代&#xff09; 代码&#xff08;后序递归&#xff09; 代码&#xff08;满二次树递归&#xff09; 总结 110.平衡二叉树 题目 代码&#xff08;后序递归&#xff09; 代码&#xff08;层序迭代&#xff0…

短视频批量采集提取软件|视频关键词下载工具

短视频批量采集软件&#xff1a;快速抓取、高效下载 一、开发背景 随着短视频平台的兴起&#xff0c;获取并分析相关视频内容已成为许多业务的必要步骤。然而&#xff0c;传统的手动方式无法满足快速、批量获取的需求&#xff0c;因此我们开发了一款专业的短视频批量采集软件。…