0%

antd pro动态切换主题

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

动态主题切换原理

主题切换主要是通过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
40
{
"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源代码(https://github.com/ant-design/ant-design-pro-layout/blob/master/src/SettingDrawer/index.tsx)。

解决主题编译慢问题

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

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

1
2
3
4
5
6
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

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

config.js

1
2
3
4
5
6
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
36
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获取主题后动态设置行内样式
-------------本文结束感谢您的阅读-------------