Ant Design 设计规范和技术上支持灵活的样式定制,以满足业务和品牌上多样化的视觉需求,包括但不限于全局样式(主色、圆角、边框)和指定组件的视觉定制。
在 5.0 版本的 Ant Design 中,我们提供了一套全新的定制主题方案。不同于 4.x 版本的 less 和 CSS 变量,有了 CSS-in-JS 的加持后,动态主题的能力也得到了加强,包括但不限于:
在 5.0 版本中我们把影响主题的最小元素称为 Design Token。通过修改 Design Token,我们可以呈现出各种各样的主题或者组件。
通过在 ConfigProvider 中传入 theme
,可以配置主题。在升级 v5 后,将默认使用 v5 的主题,以下是将配置主题示例:
import React from 'react';import { ConfigProvider, Button } from 'antd';const App: React.FC = () => (<ConfigProvidertheme={{token: {colorPrimary: '#00b96b',},}}><Button /></ConfigProvider>);export default App;
这将会得到一个以 #00b96b 为主色的主题,以 Button 组件为例可以看到相应的变化:
通过修改算法可以快速生成风格迥异的主题,5.0 版本中默认提供三套预设算法,分别是默认算法 theme.defaultAlgorithm
、暗色算法 theme.darkAlgorithm
和紧凑算法 theme.compactAlgorithm
。你可以通过修改 ConfigProvider 中 theme
属性的 algorithm
属性来切换算法。
import React from 'react';import { ConfigProvider, Button, theme } from 'antd';const App: React.FC = () => (<ConfigProvidertheme={{algorithm: theme.darkAlgorithm,}}><Button /></ConfigProvider>);export default App;
除了整体的 Design Token,各个组件也会开放自己的 Component Token 来实现针对组件的样式定制能力,不同的组件之间不会相互影响。同样地,也可以通过这种方式来覆盖组件的其他 Design Token。
import React from 'react';import { ConfigProvider, Radio, Checkbox } from 'antd';const App: React.FC = () => (<ConfigProvidertheme={{components: {Radio: {colorPrimary: '#00b96b',},},}}><Radio>Radio</Radio><Checkbox>Checkbox</Checkbox></ConfigProvider>);export default App;
通过这种方式,我们可以仅将 Radio 组件的主色改为 #00b96b 而不会影响其他组件。
在 v5 中,动态切换主题对用户来说是非常简单的,你可以在任何时候通过 ConfigProvider
的 theme
属性来动态切换主题,而不需要任何额外配置。
可以嵌套使用 ConfigProvider
来实现局部主题的更换。在子主题中未被改变的 Design Token 将会继承父主题。
import React from 'react';import { ConfigProvider, Button } from 'antd';const App: React.FC = () => (<ConfigProvidertheme={{token: {colorPrimary: '#1677ff',},}}><Button /><ConfigProvidertheme={{token: {colorPrimary: '#1890ff',},}}><Button /></ConfigProvider></ConfigProvider>);export default App;
如果你希望使用当前主题下的 Design Token,我们提供了 useToken
这个 hook 来获取 Design Token。
import React from 'react';import { Button, theme } from 'antd';const { useToken } = theme;const App: React.FC = () => {const { token } = useToken();return <Button style={{ backgroundColor: token.colorPrimary }}>Button</Button>;};export default App;
当你需要非 React 生命周期消费 Token 变量时,可以通过静态方法将其导出:
import { theme } from 'antd';const { defaultAlgorithm, defaultSeed } = theme;const mapToken = defaultAlgorithm(defaultSeed);
如果需要将其应用到静态样式编译框架,如 less 可以通过 less-loader 注入:
{loader: "less-loader",options: {lessOptions: {modifyVars: mapToken,},},}
兼容包提供了变量转换方法用于转成 v4 的 less 变量,如需使用点击此处查看详情。
在 Design Token 中我们提供了一套更加贴合设计的三层结构,将 Design Token 拆解为 Seed Token、Map Token 和 Alias Token 三部分。这三组 Token 并不是简单的分组,而是一个三层的派生关系,由 Seed Token 派生 Map Token,再由 Map Token 派生 Alias Token。在大部分情况下,使用 Seed Token 就可以满足定制主题的需要。但如果您需要更高程度的主题定制,您需要了解 antd 中 Design Token 的生命周期。
Seed Token 意味着所有设计意图的起源。比如我们可以通过改变 colorPrimary
来改变主题色,antd 内部的算法会自动的根据 Seed Token 计算出对应的一系列颜色并应用:
const theme = {token: {colorPrimary: '#1890ff',},};
Map Token 是基于 Seed 派生的梯度变量。定制 Map Token 推荐通过 theme.algorithm
来实现,这样可以保证 Map Token 之间的梯度关系。也可以通过 theme.token
覆盖,用于单独修改一些 map token 的值。
const theme = {token: {colorPrimaryBg: '#e6f7ff',},};
Alias Token 用于批量控制某些共性组件的样式,基本上是 Map Token 别名,或者特殊处理过的 Map Token。
const theme = {token: {colorLink: '#1890ff',},};
基本算法用于将 Seed Token 展开为 Map Token,比如由一个基本色算出一个梯度色板,或者由一个基本的圆角算出各种大小的圆角。算法可以单独使用,也可以任意地组合使用,比如可以将暗色算法和紧凑算法组合使用,得到一个暗色和紧凑相结合的主题。
import { theme } from 'antd';const { darkAlgorithm, compactAlgorithm } = theme;const theme = {algorithm: [darkAlgorithm, compactAlgorithm],};
使用 @ant-design/cssinjs
将所需样式抽离:
import React from 'react';import { renderToString } from 'react-dom/server';import { createCache, extractStyle, StyleProvider } from '@ant-design/cssinjs';export default () => {// SSR Renderconst cache = createCache();const html = renderToString(<StyleProvider cache={cache}><MyApp /></StyleProvider>,);// Grab style from cacheconst styleText = extractStyle(cache);// Mix with stylereturn `<!DOCTYPE html><html><head>${styleText}</head><body><div id="root">${html}</div></body></html>`;};
请参考文档 样式兼容。
在 Shadow DOM 场景中,由于其添加 <style />
标签的方式与普通 DOM 不同,所以需要使用 @ant-design/cssinjs
的 StyleProvider
配置 container
属性用于设置插入位置:
import React from 'react';import { createRoot } from 'react-dom/client';import { StyleProvider } from '@ant-design/cssinjs';const shadowRoot = someEle.attachShadow({ mode: 'open' });const container = document.createElement('div');shadowRoot.appendChild(container);const root = createRoot(container);root.render(<StyleProvider container={shadowRoot}><MyApp /></StyleProvider>,);
属性 | 说明 | 类型 | 默认值 |
---|---|---|---|
token | 用于修改 Design Token | AliasToken | - |
inherit | 继承上层 ConfigProvider 中配置的主题。 | boolean | true |
algorithm | 用于修改 Seed Token 到 Map Token 的算法 | (token: SeedToken) => MapToken | ((token: SeedToken) => MapToken)[] | defaultAlgorithm |
components | 用于修改各个组件的 Component Token 以及覆盖该组件消费的 Alias Token | OverrideToken | - |
属性 | 说明 | 类型 | 默认值 |
---|---|---|---|
Component (可以是任意 antd 组件名,如 Button ) | 用于修改 Component Token 以及覆盖该组件消费的 Alias Token | ComponentToken & AliasToken | - |
Token 名称 | 描述 | 类型 | 默认值 |
---|---|---|---|
borderRadius | 基础组件的圆角大小,例如按钮、输入框、卡片等 | number | 6 |
colorBgBase | 用于派生背景色梯度的基础变量,v5 中我们添加了一层背景色的派生算法可以产出梯度明确的背景色的梯度变量。但 **请不要在代码中直接使用该 Seed Token** ! | string | #fff |
colorError | 用于表示操作失败的 Token 序列,如失败按钮、错误状态提示(Result)组件等。 | string | #ff4d4f |
colorInfo | 用于表示操作信息的 Token 序列,如 Alert 、Tag、 Progress 等组件都有用到该组梯度变量。 | string | #1677ff |
colorPrimary | 品牌色是体现产品特性和传播理念最直观的视觉元素之一。在你完成品牌主色的选取之后,我们会自动帮你生成一套完整的色板,并赋予它们有效的设计语义 | string | #1677ff |
colorSuccess | 用于表示操作成功的 Token 序列,如 Result、Progress 等组件会使用该组梯度变量。 | string | #52c41a |
colorTextBase | 用于派生文本色梯度的基础变量,v5 中我们添加了一层文本色的派生算法可以产出梯度明确的文本色的梯度变量。但**请不要在代码中直接使用该 Seed Token**! | string | #000 |
colorWarning | 用于表示操作警告的 Token 序列,如 Notification、 Alert等警告类组件或 Input 输入类等组件会使用该组梯度变量。 | string | #faad14 |
controlHeight | Ant Design 中按钮和输入框等基础控件的高度 | number | 32 |
fontFamily | Ant Design 的字体家族中优先使用系统默认的界面字体,同时提供了一套利于屏显的备用字体库,来维护在不同平台以及浏览器的显示下,字体始终保持良好的易读性和可读性,体现了友好、稳定和专业的特性。 | string | -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji' |
fontSize | 设计系统中使用最广泛的字体大小,文本梯度也将基于该字号进行派生。 | number | 14 |
lineType | 用于控制组件边框、分割线等的样式,默认是实线 | string | solid |
lineWidth | 用于控制组件边框、分割线等的宽度 | number | 1 |
motionBase | number | 0 | |
motionEaseInBack | string | cubic-bezier(0.71, -0.46, 0.88, 0.6) | |
motionEaseInOut | string | cubic-bezier(0.645, 0.045, 0.355, 1) | |
motionEaseInOutCirc | string | cubic-bezier(0.78, 0.14, 0.15, 0.86) | |
motionEaseInQuint | string | cubic-bezier(0.755, 0.05, 0.855, 0.06) | |
motionEaseOut | string | cubic-bezier(0.215, 0.61, 0.355, 1) | |
motionEaseOutBack | string | cubic-bezier(0.12, 0.4, 0.29, 1.46) | |
motionEaseOutCirc | string | cubic-bezier(0.08, 0.82, 0.17, 1) | |
motionEaseOutQuint | string | cubic-bezier(0.23, 1, 0.32, 1) | |
motionUnit | 用于控制动画时长的变化单位 | number | 0.1 |
opacityImage | number | 1 | |
sizePopupArrow | number | 16 | |
sizeStep | 用于控制组件尺寸的基础步长,尺寸步长结合尺寸变化单位,就可以派生各种尺寸梯度。通过调整步长即可得到不同的布局模式,例如 V5 紧凑模式下的尺寸步长为 2 | number | 4 |
sizeUnit | 用于控制组件尺寸的变化单位,在 Ant Design 中我们的基础单位为 4 ,便于更加细致地控制尺寸梯度 | number | 4 |
wireframe | 用于将组件的视觉效果变为线框化,如果需要使用 V4 的效果,需要开启配置项 | boolean | false |
zIndexBase | 所有组件的基础 Z 轴值,用于一些悬浮类的组件的可以基于该值 Z 轴控制层级,例如 BackTop、 Affix 等 | number | 0 |
zIndexPopupBase | 浮层类组件的基础 Z 轴值,用于一些悬浮类的组件的可以基于该值 Z 轴控制层级,例如 FloatButton、 Affix、Modal 等 | number | 1000 |
继承所有 SeedToken 的属性
Token 名称 | 描述 | 类型 | 默认值 |
---|---|---|---|
borderRadiusLG | LG号圆角,用于组件中的一些大圆角,如 Card、Modal 等一些组件样式。 | number | 8 |
borderRadiusOuter | number | 4 | |
borderRadiusSM | SM号圆角,用于组件小尺寸下的圆角,如 Button、Input、Select 等输入类控件在 small size 下的圆角 | number | 4 |
borderRadiusXS | XS号圆角,用于组件中的一些小圆角,如 Segmented 、Arrow 等一些内部圆角的组件样式中。 | number | 2 |
colorBgContainer | 组件的容器背景色,例如:默认按钮、输入框等。务必不要将其与 `colorBgElevated` 混淆。 | string | #ffffff |
colorBgElevated | 浮层容器背景色,在暗色模式下该 token 的色值会比 `colorBgContainer` 要亮一些。例如:模态框、弹出框、菜单等。 | string | #ffffff |
colorBgLayout | 该色用于页面整体布局的背景色,只有需要在页面中处于 B1 的视觉层级时才会使用该 token,其他用法都是错误的 | string | #f5f5f5 |
colorBgMask | 浮层的背景蒙层颜色,用于遮罩浮层下面的内容,Modal、Drawer 等组件的蒙层使用的是该 token | string | rgba(0, 0, 0, 0.45) |
colorBgSpotlight | 该色用于引起用户强烈关注注意的背景色,目前只用在 Tooltip 的背景色上。 | string | rgba(0, 0, 0, 0.85) |
colorBorder | 默认使用的边框颜色, 用于分割不同的元素,例如:表单的分割线、卡片的分割线等。 | string | #d9d9d9 |
colorBorderSecondary | 比默认使用的边框色要浅一级,此颜色和 colorSplit 的颜色一致。使用的是实色。 | string | #f0f0f0 |
colorErrorActive | string | #d9363e | |
colorErrorBg | string | #fff2f0 | |
colorErrorBgHover | string | #fff1f0 | |
colorErrorBorder | string | #ffccc7 | |
colorErrorBorderHover | string | #ffa39e | |
colorErrorHover | string | #ff7875 | |
colorErrorText | string | #ff4d4f | |
colorErrorTextActive | string | #d9363e | |
colorErrorTextHover | string | #ff7875 | |
colorFill | 最深的填充色,用于拉开与二、三级填充色的区分度,目前只用在 Slider 的 hover 效果。 | string | rgba(0, 0, 0, 0.15) |
colorFillQuaternary | 最弱一级的填充色,适用于不易引起注意的色块,例如斑马纹、区分边界的色块等。 | string | rgba(0, 0, 0, 0.02) |
colorFillSecondary | 二级填充色可以较为明显地勾勒出元素形体,如 Rate、Skeleton 等。也可以作为三级填充色的 Hover 状态,如 Table 等。 | string | rgba(0, 0, 0, 0.06) |
colorFillTertiary | 三级填充色用于勾勒出元素形体的场景,如 Slider、Segmented 等。如无强调需求的情况下,建议使用三级填色作为默认填色。 | string | rgba(0, 0, 0, 0.04) |
colorInfoActive | string | #0958d9 | |
colorInfoBg | 信息色的浅色背景颜色 | string | #e6f4ff |
colorInfoBgHover | 信息色的浅色背景色悬浮态 | string | #bae0ff |
colorInfoBorder | string | #91caff | |
colorInfoBorderHover | string | #69b1ff | |
colorInfoHover | string | #69b1ff | |
colorInfoText | string | #1677ff | |
colorInfoTextActive | string | #0958d9 | |
colorInfoTextHover | string | #4096ff | |
colorPrimaryActive | 主色梯度下的深色激活态 | string | #0958d9 |
colorPrimaryBg | 主色浅色背景颜色,一般用于视觉层级较弱的选中状态。 | string | #e6f4ff |
colorPrimaryBgHover | 与主色浅色背景颜色相对应的悬浮态颜色。 | string | #bae0ff |
colorPrimaryBorder | 主色梯度下的描边用色,用在 Slider 组件的描边上 | string | #91caff |
colorPrimaryBorderHover | 主色梯度下的描边用色的悬浮态,Slider 、Button 等组件的描边 Hover 时会使用 | string | #69b1ff |
colorPrimaryHover | 主色梯度下的悬浮态,使用频率很高 | string | #4096ff |
colorPrimaryText | 主色梯度下的文本颜色 | string | #1677ff |
colorPrimaryTextActive | 主色梯度下的文本激活态 | string | #0958d9 |
colorPrimaryTextHover | 主色梯度下的文本悬浮态 | string | #4096ff |
colorSuccessActive | 成功色的深色激活态 | string | #389e0d |
colorSuccessBg | 成功色的浅色背景颜色,用于 Tag 和 Alert 的成功态背景色 | string | #f6ffed |
colorSuccessBgHover | 成功色浅色背景颜色,一般用于视觉层级较弱的选中状态,不过 antd 目前没有使用到该 token | string | #d9f7be |
colorSuccessBorder | 成功色的描边色,用于 Tag 和 Alert 的成功态描边色 | string | #b7eb8f |
colorSuccessBorderHover | 成功色的描边色悬浮态 | string | #95de64 |
colorSuccessHover | 成功色的深色悬浮态 | string | #95de64 |
colorSuccessText | 成功色的文本默认态 | string | #52c41a |
colorSuccessTextActive | 成功色的文本激活态 | string | #389e0d |
colorSuccessTextHover | 成功色的文本悬浮态 | string | #73d13d |
colorText | 最深的文本色。为了符合W3C标准,默认的文本颜色使用了该色,同时这个颜色也是最深的中性色。 | string | rgba(0, 0, 0, 0.88) |
colorTextQuaternary | 第四级文本色是最浅的文本色,例如表单的输入提示文本、禁用色文本等。 | string | rgba(0, 0, 0, 0.25) |
colorTextSecondary | 作为第二梯度的文本色,一般用在不那么需要强化文本颜色的场景,例如 Label 文本、Menu 的文本选中态等场景。 | string | rgba(0, 0, 0, 0.65) |
colorTextTertiary | 第三级文本色一般用于描述性文本,例如表单的中的补充说明文本、列表的描述性文本等场景。 | string | rgba(0, 0, 0, 0.45) |
colorWarningActive | 警戒色的深色激活态 | string | #d48806 |
colorWarningBg | string | #fffbe6 | |
colorWarningBgHover | 警戒色的浅色背景色悬浮态 | string | #fff1b8 |
colorWarningBorder | 警戒色的描边色 | string | #ffe58f |
colorWarningBorderHover | 警戒色的描边色悬浮态 | string | #ffd666 |
colorWarningHover | 警戒色的深色悬浮态 | string | #ffd666 |
colorWarningText | 警戒色的文本默认态 | string | #faad14 |
colorWarningTextActive | 警戒色的文本激活态 | string | #d48806 |
colorWarningTextHover | 警戒色的文本悬浮态 | string | #ffc53d |
colorWhite | 不随主题变化的纯白色 | string | #fff |
controlHeightLG | number | 40 | |
controlHeightSM | number | 24 | |
controlHeightXS | number | 16 | |
fontSizeHeading1 | H1 标签所使用的字号 | number | 38 |
fontSizeHeading2 | h2 标签所使用的字号 | number | 30 |
fontSizeHeading3 | h3 标签使用的字号 | number | 24 |
fontSizeHeading4 | h4 标签使用的字号 | number | 20 |
fontSizeHeading5 | h5 标签使用的字号 | number | 16 |
fontSizeLG | number | 16 | |
fontSizeSM | number | 12 | |
fontSizeXL | number | 20 | |
lineHeight | number | 1.5714285714285714 | |
lineHeightHeading1 | number | 1.2105263157894737 | |
lineHeightHeading2 | number | 1.2666666666666666 | |
lineHeightHeading3 | number | 1.3333333333333333 | |
lineHeightHeading4 | number | 1.4 | |
lineHeightHeading5 | number | 1.5 | |
lineHeightLG | number | 1.5 | |
lineHeightSM | number | 1.6666666666666667 | |
lineWidthBold | 描边类组件的默认线宽,如 Button、Input、Select 等输入类控件。 | number | 2 |
motionDurationFast | string | 0.1s | |
motionDurationMid | string | 0.2s | |
motionDurationSlow | string | 0.3s | |
size | 默认尺寸 | number | 16 |
sizeLG | number | 24 | |
sizeMD | number | 20 | |
sizeMS | number | 16 | |
sizeSM | number | 12 | |
sizeXL | number | 32 | |
sizeXS | number | 8 | |
sizeXXL | number | 48 | |
sizeXXS | number | 4 |
继承所有 SeedToken 和 MapToken 的属性
Token 名称 | 描述 | 类型 | 默认值 |
---|---|---|---|
boxShadow | string | 0 1px 2px 0 rgba(0, 0, 0, 0.03), 0 1px 6px -1px rgba(0, 0, 0, 0.02), 0 2px 4px 0 rgba(0, 0, 0, 0.02) | |
boxShadowSecondary | string | 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 9px 28px 8px rgba(0, 0, 0, 0.05) | |
colorBgContainerDisabled | string | rgba(0, 0, 0, 0.04) | |
colorBgTextActive | string | rgba(0, 0, 0, 0.15) | |
colorBgTextHover | string | rgba(0, 0, 0, 0.06) | |
colorBorderBg | string | #ffffff | |
colorErrorOutline | string | rgba(255, 38, 5, 0.06) | |
colorFillAlter | string | rgba(0, 0, 0, 0.02) | |
colorFillContent | string | rgba(0, 0, 0, 0.06) | |
colorFillContentHover | string | rgba(0, 0, 0, 0.15) | |
colorHighlight | string | #ff4d4f | |
colorIcon | string | rgba(0, 0, 0, 0.45) | |
colorIconHover | string | rgba(0, 0, 0, 0.88) | |
colorLink | string | #1677ff | |
colorLinkActive | string | #0958d9 | |
colorLinkHover | string | #69b1ff | |
colorSplit | 用于作为分割线的颜色,此颜色和 colorBorderSecondary 的颜色一致,但是用的是透明色。 | string | rgba(5, 5, 5, 0.06) |
colorTextDescription | string | rgba(0, 0, 0, 0.45) | |
colorTextDisabled | string | rgba(0, 0, 0, 0.25) | |
colorTextHeading | string | rgba(0, 0, 0, 0.88) | |
colorTextLabel | string | rgba(0, 0, 0, 0.65) | |
colorTextLightSolid | string | #fff | |
colorTextPlaceholder | string | rgba(0, 0, 0, 0.25) | |
colorWarningOutline | string | rgba(255, 215, 5, 0.1) | |
controlInteractiveSize | number | 16 | |
controlItemBgActive | string | #e6f4ff | |
controlItemBgActiveDisabled | string | rgba(0, 0, 0, 0.15) | |
controlItemBgActiveHover | string | #bae0ff | |
controlItemBgHover | string | rgba(0, 0, 0, 0.04) | |
controlOutline | string | rgba(5, 145, 255, 0.1) | |
controlOutlineWidth | number | 2 | |
controlPaddingHorizontal | number | 12 | |
controlPaddingHorizontalSM | number | 8 | |
controlTmpOutline | string | rgba(0, 0, 0, 0.02) | |
fontSizeIcon | number | 12 | |
fontWeightStrong | number | 600 | |
linkDecoration | undefined | TextDecoration<string | number> | none | |
linkFocusDecoration | undefined | TextDecoration<string | number> | none | |
linkHoverDecoration | undefined | TextDecoration<string | number> | none | |
margin | number | 16 | |
marginLG | number | 24 | |
marginMD | number | 20 | |
marginSM | number | 12 | |
marginXL | number | 32 | |
marginXS | number | 8 | |
marginXXL | number | 48 | |
marginXXS | number | 4 | |
opacityLoading | number | 0.65 | |
padding | number | 16 | |
paddingContentHorizontal | number | 16 | |
paddingContentHorizontalLG | number | 24 | |
paddingContentHorizontalSM | number | 16 | |
paddingContentVertical | number | 12 | |
paddingContentVerticalLG | number | 16 | |
paddingContentVerticalSM | number | 8 | |
paddingLG | number | 24 | |
paddingMD | number | 20 | |
paddingSM | number | 12 | |
paddingXL | number | 32 | |
paddingXS | number | 8 | |
paddingXXS | number | 4 | |
screenLG | number | 992 | |
screenLGMax | number | 1199 | |
screenLGMin | number | 992 | |
screenMD | number | 768 | |
screenMDMax | number | 991 | |
screenMDMin | number | 768 | |
screenSM | number | 576 | |
screenSMMax | number | 767 | |
screenSMMin | number | 576 | |
screenXL | number | 1200 | |
screenXLMax | number | 1599 | |
screenXLMin | number | 1200 | |
screenXS | number | 480 | |
screenXSMax | number | 575 | |
screenXSMin | number | 480 | |
screenXXL | number | 1600 | |
screenXXLMin | number | 1600 |
请参考 @ant-design/cssinjs
。
我们提供了帮助用户调试主题的工具:主题编辑器
你可以使用此工具自由地修改 Design Token,以达到您对主题的期望。
theme
从 undefined
变为对象或者变为 undefined
时组件重新 mount 了?在 ConfigProvider 中我们通过 DesignTokenContext
传递 context,theme
为 undefined
时不会套一层 Provider,所以从无到有或者从有到无时 React 的 VirtualDOM 结构变化,导致组件重新 mount。解决方法:将 undefined
替换为空对象 {}
即可。