实现原理
-
自定义属性(__*):css 变量
- 通过 var 函数在全文档范围内复用的
- 定义在根伪类:root 下,这样就可以在 HTML 文档的任何地方访问到它
- 注意点: :root 这个 CSS 伪类匹配文档树的根元素。对于 HTML 来说,:root 表示 元素,除了优先级更高之外,与 html 选择器相同。
- 注意点:var 变量方式 ie 不支持;css-vars-ponyfill 插件 ,使页面展示一个默认色
-
步骤
按antd官方文档,要动态切换主题不能引用@import '~antd/dist/antd.less';而需要引用@import '~antd/dist/antd.variable.min.css'; 在src/global.less下引入@import '~antd/dist/antd.variable.min.css'; 如果没有global.less自己创建一个引入@import '~antd/dist/antd.variable.min.css'; 引入完毕后,配置动态主题色Config。(此处我使用useModel作为状态管理,有用Redux的也可以换成Redux) const Layout: React.FC = (props) => { const { theme } = useModel('tabMenu'); ConfigProvider.config({ theme: { primaryColor: theme, }, }); return ( <ConfigProvider locale={locale}> <IndexPage {...props} /> </ConfigProvider> ); }; 配置好后,切换主题色。改变状态参数theme即可。 例如: const { theme, dispatch } = useModel('tabMenu'); return ( <div className="main"> <ColorRGBPicker value={theme} onChange={(e) => { dispatch({ type: 'CHANGE_THEME', payload: { theme: e } }); }} /> </div> ); 切换主题一共就这三处地方,极为简单。 -
ConfigProvider.config() —— antd 提供的
ConfigProvider.config = setGlobalConfig; var setGlobalConfig = function setGlobalConfig(_ref) { var prefixCls = _ref.prefixCls, iconPrefixCls = _ref.iconPrefixCls, theme = _ref.theme; if (prefixCls !== undefined) { globalPrefixCls = prefixCls; } if (iconPrefixCls !== undefined) { globalIconPrefixCls = iconPrefixCls; } if (theme) { (0, \_cssVariables.registerTheme)(getGlobalPrefixCls(), theme); // 更改主题色 } /**************antd 内部实现方式******************/ /** * 1. 传入主题色 * 2. 生成主题色相关的十个色阶 * 3. 调用 rc-util 下 updateCss 生成的变量放到 :root 根伪类下面 */ import { updateCSS } from 'rc-util/lib/Dom/dynamicCSS'; import { TinyColor } from '@ctrl/tinycolor'; import { generate } from '@ant-design/colors'; function setThemeColor({ themeColor, varName }) { const variables = {}; // ================ Primary Color ================ if (themeColor) { // 转成 TinyColor 色值格式 const primaryColor = new TinyColor(themeColor); // 10个不同阶梯色值 const colorPalettes = generate(primaryColor.toRgbString()); // Legacy - We should use semantic naming standard variables[`${varName}`] = themeColor; colorPalettes.forEach((color, index) => { variables[`${varName}-${index + 1}`] = color; }); } // Convert to css variables // cssList ['--theme-color: xxx','--theme-color-1: xxx',...,'--theme-color-10: xxx' ] const cssList = Object.keys(variables).map( key => `--${key}: ${variables[key]};`, ); // updateCSS 更新业务代码中的主题色: 创建 style 标签,值为cssList,并作为最后一个子元素插在head标签下 updateCSS( '\n :root {\n '.concat(cssList.join('\n'), '\n }\n '), '-mkui-fd-'.concat(Date.now(), '-').concat('-dynamic-theme'), ); }