【问题标题】:Dynamically changing Less variables in React Gatsby app with Ant Design at runtime在运行时使用 Ant Design 在 React Gatsby 应用程序中动态更改 Less 变量
【发布时间】:2021-10-31 02:21:05
【问题描述】:

我们正在使用 React、GatsbyJs 和 Ant Design 构建一个白标平台。我们被 Gatsby 和 Ant Design 困住了,因为我们正在从现有系统迁移,并且改变其中任何一个都会带来巨大的影响。此外,我们必须有一个部署。为每个白标构建一个版本不是一种选择。

因此,我们需要能够在运行时更改样式(主要是颜色)。

问题是:Ant Design 使用 less 变量来定义它的主题,我们无法在运行时更改它们,即使使用 less 的 modifyVars 也是如此。

问题是我们必须更改更少的变量,而不是全局 CSS 或使用其他方式

Ant Design 多次推导主变量以获得相邻属性。因此,例如,如果我们将@primary-color 定义为红色,那么当我们向屏幕添加一个 Button 时,Ant Design 还会定义它的边框颜色、悬停颜色以及许多其他不同深浅的红色细节。

这意味着,如果我们要使用其他样式工具,我们将需要生成这些颜色派生并替换每个组件的每个小属性。这将是混乱的。

场景

我们正在使用 gatsby-plugin-antdgatsby-plugin-less 来减少加载并在构建时更改变量。我们的 gatsby-config.js 看起来像这样:

module.exports = {
  siteMetadata: {
    siteUrl: 'https://www.yourdomain.tld',
    title: 'yourtitle'
  },
  plugins: [
    'gatsby-plugin-root-import',
    'gatsby-plugin-typescript',
    {
      resolve: 'gatsby-plugin-antd',
      options: {
        style: true
      }
    },
    {
      resolve: 'gatsby-plugin-less',
      options: {
        lessOptions: {
          javascriptEnabled: true,
          modifyVars: {
            'primary-color': '#FFFFFF',
            'link-color': '#000000',
            'success-color': '#FFFFFF',
            'warning-color': '#000000'
          }
        }
      }
    }
  ]
};

我们在 gatsby-browser.js 文件中导入样式:

import './src/styles/index';

我们的样式/索引有:

import 'tachyons';
import './global.css';
import './antd.less';

antd.less:

@import '~antd/dist/antd.less';

而且 global.css 有一些通用的项目 CSS。

在构建时使用定义的变量可以正常工作。

到目前为止我们所做的尝试......

我们已经试用了这个插件: https://github.com/mzohaibqc/antd-theme-webpack-plugin 据说这正是我们需要的。但是没有使用 Gatsby 的例子。

然后我们尝试使用 gatsby-node.js 添加插件,如下所述: https://www.gatsbyjs.com/docs/how-to/custom-configuration/add-custom-webpack-config/

首先,我们尝试使用 index.html 作为插件的 indexFileName。它只是不起作用。

然后,按照插件文档,我们尝试使用 indexFileName 作为 false 并在我们的 pages/index.tsx 中使用 Helmet 导入以下脚本:

<script> window.less = { async: false, env: 'production' }; 
</script> <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/less.js/2.7.2/less.min.js"></script> ```

也没有用。如果我们将 indexFileName 定义为 false,我们会通过堆获得内存。 如果我们将 indexFileName 保持为 'index.html' 并添加脚本,我们就可以调用 window.less.modifyVars 并且它成功返回(我们正在记录 Promise 的 thenerror) 但不影响 antd 的变量。

然后我们尝试做一些类似的事情,但是我们没有从外部加载更少,而是将其安装为 node_module 并将其导入文件并以类似的方式直接使用它。得到同样的结果: modifyVars 运行并返回成功,但不影响 antd。

然后,我们尝试了一些不同的方法:我们删除了 gatsby 插件并尝试直接从 antd 导入 less,如下所示: https://ant.design/docs/react/customize-theme 所以我们像这样导入它:

@import '~antd/lib/style/themes/default.less';
@import '~antd/dist/antd.less';
@import 'your-theme-file.less';

还有,不好。它与之前的场景不同,因为样式会在您保存代码后更新。无需阻止盖茨比,作为第一个解决方案。但是, modifyVars 对 antd 组件仍然没有影响。

然后,为了隔离问题,我们尝试设置一个基本 HTML 组件的样式 - 一个按钮 - 以检查问题是否与 gatsby 或 antd 有关。而且......仍然没有成功。 less.modifyVars 无法在运行时更改基本按钮样式。

所以,我们认为这可能是 Gatsby 和 Less 之间的事情。我们检查了 gatsby-plugin-antdgatsby-plugin-less 看看我们是否能找到一些东西,但没有发现任何有用的东西。

我们假设 gatsby 的 less-loader 在构建期间使用的“更少实例”或“更少上下文”与我们调用 modifyVars 的不同。所以它不会影响原始变量。

完全卡住了。请帮忙!

编辑 - 解决方案

Ant Design 团队刚刚发布了 - 今天 - 一个新的 alpha 版本,其中包括使用 CSS 变量的动态主题。

https://ant.design/docs/react/customize-theme-variable

到目前为止,它工作正常。关闭问题。

编辑 2

关于接受的答案有更详细的解决方案。

【问题讨论】:

    标签: reactjs less gatsby antd


    【解决方案1】:

    Ant Design 团队刚刚发布了 - 今天 - 一个新的 alpha 版本,其中包括使用 CSS 变量的动态主题。

    https://ant.design/docs/react/customize-theme-variable

    到目前为止一切正常。

    编辑 - 详细解决方案

    我从项目中删除了 gatsby-plugin-antd 和 gatsby-plugin-less。也去掉了antdless文件的导入。

    相反,在我的 styles/index.tsx(在 gatsby-browser.js 中导入)中,我正在导入 variables.min.css 文件:

    import 'antd/dist/antd.variable.min.css';
    

    然后,每当我想更改 Ant Design 变量时,我只需使用:

    import { ConfigProvider } from 'antd';
    
    ...
    
    ConfigProvider.config({
      theme: {
        primaryColor: '#[DESIRED_COLOR_HEX]'
      }
    });
    
    

    提供者

    由于每次加载网站时都必须这样做,我正在创建一个 ThemeProvider 来包装每个页面并定义主题。它从后端获取主题数据并设置 Ant Design 主题变量。

    示例代码:

    
    import { Spin } from 'antd';
    import React, { useEffect, useState } from 'react';
    import { ConfigProvider } from 'antd';
    import { Theme } from './theme.interface';
    
    interface Props {
      children: React.ReactNode;
    }
    
    export const ThemeProvider = ({ children }: Props): JSX.Element => {
      const [themeVars, setThemeVars] = useState<Theme>(null);
    
      useEffect(() => {
        async function fetchMyAPI() {
          const result = await getThemeFromBackend(); // Make API call with Axios
          if (result) setThemeVars(result);
        }
        fetchMyAPI();
      }, []);
    
      useEffect(() => {
        if (themeVars) {
          ConfigProvider.config({
            theme: {
              primaryColor: `#${themeVars.primaryColor}`
            }
          });
        }
      }, [themeVars]);
    
      return <div>{!themeVars ? <Spin size="large" /> : <>{children}</>}</div>;
    };
    
    

    而且可以这样使用:

    ...
    <ThemeProvider>
      <h1>My page header</h1>
      <p>Page content...</p>
    </ThemeProvider>
    ...
    

    注意:您可以将主题数据保存在本地存储中以提高性能,因此您不必在每次网站重新加载时都调用后端。也许你只需要不时刷新它。

    【讨论】:

    • 请添加更多详细信息以扩展您的答案,例如工作代码或文档引用。
    • 完成。引用的文档非常简单,但我使用我们采取的确切步骤编辑了答案,并为包装功能的提供者提供了建议。
    猜你喜欢
    • 2021-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多