antd pro 官方文档介绍了动态切换主题的方法。但是并没有讲的特别清楚,而且编译主题的时间比较长,非常影响开发效率。下面介绍下我的解决办法。

# 自定义主题样式

# 动态主题切换原理

主题切换主要是通过 unm-plugin-antd-theme 插件实现的,unm-plugin-antd-theme 插件通过 antd-pro-merge-less 将 less 文件编译为一个主题 css 文件。
所以 unm-plugin-antd-theme 的配置文件就是定义的 antd-pro-merge-less (https://github.com/chenshuai2144/antd-pro-merge-less) 的参数,如下所示,要求是 json 文件,文件名 theme.config.json:

‘’ ‘’
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
{
"theme": [{
"key": "dark",
"theme": "dark",
"fileName": "dark.css",
"modifyVars": {
"@font-size-base": "12px",
"@table-padding-vertical": "10px",
"@link-color": "#0070cc"
}
},
{
"key": "volcano",
"fileName": "volcano.css",
"modifyVars": {
"@primary-color": "#FA541C",
"@font-size-base": "12px",
"@table-padding-vertical": "10px",
"@link-color": "#0070cc"
}
},
{
"key": "volcano",
"theme": "dark",
"fileName": "dark-volcano.css",
"modifyVars": {
"@primary-color": "#FA541C",
"@font-size-base": "12px",
"@table-padding-vertical": "10px",
"@link-color": "#0070cc"
}
}
],
"min": true,
"isModule": true,
"ignoreAntd": false,
"ignoreProLayout": false,
"cache": true
}

每种主题一个不同的文件,fileName 定义了文件名,theme 为 dark 表示暗黑主题(对应 antdpro 主题设置里面的 realDark),不写就是亮色主题(对应 antdpro 主题设置里面的 light 或 dark)。modifyVars 就是对 antd 默认变量的定制。

如果发现上面没有默认的亮色主题,因为这时不用单独的主题 css 文件,直接用默认的就好。
每次编译的时候 unm-plugin-antd-theme 插件会遍历上面定义的每个主题,编译为一个 css 文件,开发时位于 node_modules/.plugin-theme/theme 目录下,发布时位于 theme 目录下,每个主题文件编译都需要几秒钟,所以主题多了编译时间会比较慢,后面会讲怎么解决这个问题。
关于插件的使用,umi3 对于 umi-plugin 开头的插件是自动加载的,不需定义在 config 文件的 plugins 中,如果看到一些老的教程不要感到困惑。

好了,有了主题文件,接下来要解决怎么应用主题,其实很简单,就是重新加载新的 css 文件。antd pro 官方给了参考例子,也可以参考 SettingDrawer 源代码

# 解决主题编译慢问题

开发期每次都编译主题是难以忍受的,所以我的办法是开发器能够配置是否编译主题,而发布时总是编译主题。可惜 unm-plugin-antd-theme 插件本身并没有提供这种配置能力。好在 umi 的扩展能力非常强,我写了一个插件来解决这个问题,其实非常简单,代码只有几行,插件名 umi-plugin-config

也可以使用 umi 禁用插件的方法, unm-plugin-antd-theme 插件插件的 key 为 antdTheme,修改 config 文件如下:

‘’ ‘’
1
2
3
4
5
6
7
import { defineConfig } from 'umi';
const { REACT_APP_ENV } = process.env;
export default defineConfig({
...
antdTheme: REACT_APP_ENV !== 'dev',
...
});

# 主题配件文件优化

unm-plugin-antd-theme 插件的配置文件为 json 格式,很不方便,一来不好加入注释,二来不好共享一些变量,毕竟多个主题有一些一样的成分。为了解决这个问题,还是用到 umi 插件的扩展能力,在插件中将 js 定义转换为 json 定义,详见上述 umi-plugin-config 插件。

通过例子说明这样做的好处。你是否还记得默认的亮色主题没有编译为单独的主题 css,那么所有主题统一修改的变量如果做呢。

默认的主题还是可以通过 umi 的配置文件的 theme 配置:

theme.js theme.js
1
2
3
4
5
6
7
export default {
...
"@font-size-base": "12px",
"@table-padding-vertical": "10px",
"@link-color": "#0070cc",
...
};

config.ts config.ts
1
2
3
4
5
6
7
8
import { defineConfig } from 'umi';
import theme from './theme';
const { REACT_APP_ENV } = process.env;
export default defineConfig({
...
theme,
...
});

然后其他主题就需要在 unm-plugin-antd-theme 插件的 json 配置文件中,每个主题的 modifyVars 中都要加入,本文一开始已经给出了例子。

显而易见上面的统一变量修改需要烦人的重复,将 json 改成 js 后就能完美解决这个问题,theme.config.json 会变成如下,需要使用 CommonJS 规范定义模块:

‘’ ‘’
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
const theme = require('./theme').default;
module.exports = {
"theme": [
{
"key": "dark",
"theme": "dark",
"fileName": "dark.css",
"modifyVars": {
...theme
}
},
{
"key": "volcano",
"fileName": "volcano.css",
"modifyVars": {
"@primary-color": "#FA541C",
...theme
}
},
{
"key": "volcano",
"theme": "dark",
"fileName": "dark-volcano.css",
"modifyVars": {
"@primary-color": "#FA541C",
...theme
}
}
],
"min": true,
"isModule": true,
"ignoreAntd": false,
"ignoreProLayout": false,
"cache": true
};

这样就可以将统一的变量修改复用起来。umi-plugin-config 插件检测到 theme.config.js 文件就会自动转换为 theme.config.json 文件。

# 自定义主题注意事项

要支持动态切换主题,需要严格规范样式的定义方式。

  1. 不要使用固定的颜色,尽量使用 antd 已有变量,例如 @text-color,表示文字颜色,在亮色和暗黑模式下值是不一样的,antd-pro-merge-less 已经为我们自动处理了,我们只需要使用 @text-color
  2. 所有主题统一修改的变量定义在上述 theme.js 中,所有主题复用
  3. 主题不一样的变量修改在各自的配置中定义
  4. 所有主题统一修改的样式定义在 global.less 文件中,需要设置最高优先级
  5. 所有主题用的同一个变量但是值不一样(亮色和暗黑不一样),定义在组件 less 中,需要使用:global
  6. 如果无法通过 less 定义样式,可以通过 settings 获取主题后动态设置行内样式
更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

Brown Lee 微信支付

微信支付

Brown Lee 支付宝

支付宝

Brown Lee qqpay

qqpay