在 React 中使用 Less + CSS Modules 切换主题

Ita*_*nor 7 css themes less reactjs css-modules

在我的项目中,我使用带有 Less 的 CSS 模块,这意味着我可以两全其美。

我的src文件夹看起来像这样:

components/
    [all components]
theme/
    themes/
        lightTheme.less
        darkTheme.less
    palette.less
Run Code Online (Sandbox Code Playgroud)

调色板.less

components/
    [all components]
theme/
    themes/
        lightTheme.less
        darkTheme.less
    palette.less
Run Code Online (Sandbox Code Playgroud)

然后,在每个想要使用主题颜色的组件中,我这样做:

组件.module.less :

@import './themes/lightTheme.less';
Run Code Online (Sandbox Code Playgroud)

这种结构让我可以编辑palette.less以导入我想要使用的主题。问题是我想让用户自己选择他们喜欢的主题。主题应该可以在运行时切换,这意味着我需要以某种方式编译两个主题。


我想象完美的解决方案是这样的:

无应用程序

@import '../../theme/palette.less';

.element {
    background-color: @primary;
}
Run Code Online (Sandbox Code Playgroud)

然后以某种方式@theme在每个组件中导入这个变量并从中读取属性(即@theme[primary])。

不幸的是,Less 变量范围不是这样工作的。


我对任何使用 Less 模块的解决方案持开放态度。

谢谢!

LuD*_*nin 3

我知道您可能正在寻找使用 Less / CSS 模块的解决方案,但您的情况很可能只能通过使用 css 变量来解决(正如 Morpheus 对您的问题的评论)。

它将如何运作?

您必须确保所有样式不使用硬编码值,即而不是:

.awesome-div {
  background-color: #fefefe;
}
Run Code Online (Sandbox Code Playgroud)

你将会拥有:

:root {
  --awesome-color: #fefefe;
}

.awesome-div {
  background-color: var(--awesome-color);
}
Run Code Online (Sandbox Code Playgroud)

在明暗之间变化

此方法中有两种更改主题的方法:

  • 在 React 中使用普通 Js 代码来更新:rootCSS 元素,查看此codepen了解更多信息;
  • 只需加载一个:root在其 component.css 文件中包含所有新变量的组件;

在 React 中(也在普通 CSS 中),您可以轻松地让多个组件/元素:root在其 .css 文件中声明自己的组件/元素。

此外,任何新的值:root都会覆盖先前的冲突值:root。例如,如果在文件 app.css 中我们有:root { --color: red; },并且在加载另一个组件(例如组件 A)时,在 component_a.css 中我们覆盖了相同的变量,例如:root { --color: blue; }在浏览器中呈现的变量将是组件 A 中的变量。

按照这个逻辑,您可以拥有一个不执行任何操作和呈现任何内容的虚拟组件,而是在这个 component.js 文件中导入主题的 .css,例如:

import './light.css'; // suppose this is the light-theme dummy component
Run Code Online (Sandbox Code Playgroud)

在应用程序中切换主题时,您只需从场景中删除虚拟组件并调用另一个即可。

我对 codepen 的经验还不够丰富,无法为您提供一个包含导入/模块的示例,但我希望上面的解释能让您了解我的意思。尽管如此,这里还是我想要演示的一个简短的伪代码:


loadTheme() {
  if (this.state.theme === 'dark') return <LightTheme />;
  if (this.state.theme === 'user-3232') return <UserTheme />;
  return <DarkTheme />;
}

render() {
  return (
    <App>
      {this.loadTheme()}
      <OtherContent>
    </App>
  );
}

Run Code Online (Sandbox Code Playgroud)