前言✨
根据项目需求(其实也是个人的需求),做一个可以动态更换主题色的功能点。项目用的是umi 3.5 + antd 4.21.3
一、编译多份预设主题
编译构建的时候就有多份预设主题,在运行时只做样式切换,但是需要写多份样式,成本较高,而且css代码量也较多,最大的问题是如何直接赋值给antd组件,和设置阶梯色,遂pass
二、CSS变量
CSS变量是CSS3标准的新功能,本博客用户端用的就是这种方案,使用less @mixin 结合css变量,通过切换<html>标签属性data-color-mode来修改样式选择。这是非常不错的方案,性能好,除了IE其他浏览器兼容都没问题。但是在使用第三方组件如antd下就不那么好用了,因为antd变量什么的都自成一派。最大的问题是如何直接赋值给antd组件,和设置阶梯色,遂pass
// theme.scss
@mixin colors-light {
//品牌色
--color-text-brand: #087ea4;
}
@mixin colors-dark {
//品牌色
--color-text-brand: #149eca;
}
:root,
[data-color-mode="light"] {
@include colors-light;
}
[data-color-mode="dark"] {
@include colors-dark;
}
// theme.ts
/**
* 页面刷新时从localStorage加载主题
*/
const initTheme = () => {
const mode = localStorage.getItem("data-color-mode");
mode && document.querySelector("html")?.setAttribute("data-color-mode", mode);
};
/**
* 设置主题
*/
const setTheme = (theme: string) => {
document.querySelector("html")?.setAttribute("data-color-mode", theme);
localStorage.setItem("data-color-mode", theme);
};
/**
* 获取主题
*/
const getTheme = () => {
const mode = localStorage.getItem("data-color-mode");
return mode || 'light'
};
export { initTheme, setTheme, getTheme };
使用如下:
import React, { useEffect, useState } from 'react';
import type { FC } from 'react';
import { setTheme, getTheme } from '@/utils/theme';
const ThemeIcon: FC = () => {
const [active, setActive] = useState('light');
useEffect(() => {
setActive(getTheme())
}, [])
const handleChange = (val: string) => {
setActive(val === 'light' ? 'dark' : 'light');
setTheme(val);
};
useEffect(() => {
setTheme(active);
}, [active]);
return (
<>
</>
);
};
export default ThemeIcon;
div {
color: var(--color-text-brand);
}
三、使用Antd提供的CSS变量
这和方法二师出同源,唯一区别是方法二采用自己维护的一套样式变量,这种是直接采用antd内置的变量。
- 优点:自带变量名和阶梯色,只需要一个主色调即可完成组件色彩搭配。
- 缺点:不支持IE,该功能在 antd@4.17.0-alpha.0 版本起支持
1.引入 antd.variable.min.css
umi根目录 global.less文件下
-- @import '~antd/dist/antd.min.css';
++ @import '~antd/dist/antd.variable.min.css';
2.关闭antd按需加载
umi会自动对antd进行按需引入,在.umirc.ts关闭
antd: {
disableBabelPluginImport: true
}
3.使用ConfigProvider配置
在umi入口文件配置即可
import { ConfigProvider } from 'antd';
ConfigProvider.config({
theme: { primaryColor: '25b864' } // 做切换的话primaryColor改成变量即可
});
4.使用antd内置变量名
以上操作做完antd本身的组件就已经支持动态切换主题色了,但是自己写的组件、文本还不行,所以要使用和antd组件一样的css变量名。如果不清楚某些组件叫什么名字,直接F12自提,或者翻阅源码。
.view {
color: var(--ant-primary-color);
}
效果如下: