Ant design v4中如何动态切换主题?

Posted

技术标签:

【中文标题】Ant design v4中如何动态切换主题?【英文标题】:How to switch between themes in Ant design v4 dynamically? 【发布时间】:2020-06-14 22:18:33 【问题描述】:

我想用 Ant design v4 实现在深色/浅色主题之间动态切换

可以使用其他 CSS/LESS 导入自定义主题,如下所示: https://ant.design/docs/react/customize-theme#Use-dark-theme

但我不确定如何从代码中动态切换这些主题。我的 React 应用程序 (darkMode) 中有一个变量,它指示当前是否使用深色主题。更改此变量时,我必须提供正确的 CSS 文件。但是我不能仅在满足某些条件时才动态导入 CSS,因为这不是导入的工作方式。

我试图用require 做一些乱七八糟的事情,就像下面的代码一样,但这是一个非常非常糟糕的方法,它仍然不能正常工作(因为 CSS 被注入但可能没有被撤回。 ):

const Layout = () => 
  ...
  useEffect(() => 
    if (darkMode === true) 
      require("./App.dark.css")
     else 
      require("./App.css")
    
  , [darkMode])

  return (
    <Home />
  )

应该可以以某种方式切换主题,因为它已经在 Ant 设计文档 (https://ant.design/components/button/) 中实现:

你知道怎么做吗?

谢谢!

【问题讨论】:

ant.design/components/button 的网站是开源的吗?我似乎无法在他们的存储库中找到它。他们的许多网站都是开源的。看看他们如何在自己的网站上实现这一点会非常有用。 对我来说最好的选择是使用 dev.to/maqi1520/… 中描述的 post-css 插件。它仅创建带有深色的附加 .dark 类。基本上,该类可以作为默认主题和深色主题之间的差异。编写工具组件很容易,并且没有客户端处理样式表(慢)或加载或切换时闪烁等缺点。它与custom-cra 兼容。需要注意的是构建存在问题 - 有时它会产生损坏的 css。试图解决这些。将添加评论。 【参考方案1】:

这是我现在使用的 -

PS-

    我不知道这是否会产生最佳的捆绑大小。 更改主题会导致页面重新加载。

创建一个名为“themes”的文件夹 - 它将有 6 个文件 -> dark-theme.css、dark-theme.jsx、light-theme.css、light-theme.jsx、use-theme.js、theme-提供者.jsx。下面分别介绍它们。

dark-theme.css

import "~antd/dist/antd.dark.css";

黑暗主题.jsx

import "./dark-theme.css";
const DarkTheme = () => <></>;
export default DarkTheme;

light-theme.css

@import "~antd/dist/antd.css";

light-theme.jsx

import "./light-theme.css";
const LightTheme = () => <></>;
export default LightTheme;

use-theme.js 不同组件可以使用的自定义钩子 -

import  useEffect, useState  from "react";

const DARK_MODE = "dark-mode";

const getDarkMode = () => JSON.parse(localStorage.getItem(DARK_MODE)) || false;

export const useTheme = () => 
  const [darkMode, setDarkMode] = useState(getDarkMode);

  useEffect(() => 
    const initialValue = getDarkMode();
    if (initialValue !== darkMode) 
      localStorage.setItem(DARK_MODE, darkMode);
      window.location.reload();
    
  , [darkMode]);

  return [darkMode, setDarkMode];
;

theme-provider.jsx

import  lazy, Suspense  from "react";
import  useTheme  from "./use-theme";

const DarkTheme = lazy(() => import("./dark-theme"));
const LightTheme = lazy(() => import("./light-theme"));

export const ThemeProvider = ( children ) => 
  const [darkMode] = useTheme();

  return (
    <>
      <Suspense fallback=<span />>
        darkMode ? <DarkTheme /> : <LightTheme />
      </Suspense>
      children
    </>
  );
;

将 index.js 更改为 -

ReactDOM.render(
  <React.StrictMode>
    <ThemeProvider>
      <App />
    </ThemeProvider>
  </React.StrictMode>,
  document.getElementById("root")
);

现在,在我的导航栏中,假设我有一个切换主题的开关。这就是它的样子 -

const [darkMode, setDarkMode] = useTheme();
<Switch checked=darkMode onChange=setDarkMode />

【讨论】:

【参考方案2】:

Ant Design 新开始支持动态主题支持。但它的实验用途。您可以在此link 上找到详细信息。

【讨论】:

你有没有一个例子显示动态在深色/浅色主题之间切换... 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review【参考方案3】:

条件要求不会阻止使用以前需要的模块。因此,只要您的条件匹配,您的应用程序中就会出现要求。因此,将使用您所需的两个模块。而不是要求它们,插入样式表并删除以在它们之间切换:

const head = document.head
const dark = document.createElement('link')
const light = document.createElement('link')
dark.rel = 'stylesheet'
light.rel = 'stylesheet'
dark.href = 'antd.dark.css'
light.href = 'antd.light.css'

useEffect(() => 
  const timer = setTimeout(() => 
    if (darkMode) 
      if (head.contains(light)) 
        head.removeChild(light)
      
      head.appendChild(dark)
     else 
      if (head.contains(dark)) 
        head.removeChild(dark)
      
      head.appendChild(light)
    
  , 500)
 return () => clearTimeout(timer)
, [darkMode])

【讨论】:

【参考方案4】:

在Ant's example 中,一个建议是将“暗模式”CSS 或LESS 文件导入主样式表。

// inside App.css
@import '~antd/dist/antd.dark.css';

不是尝试切换样式表,而是将“深色”样式与基本样式组合在一个样式表中。有不同的方法可以做到这一点,但常见的模式是:

    在您的 CSS 中具有某种 dark-mode 选择器 将该选择器放入您的 html 中 有办法打开或关闭它。

这是一个工作示例:

https://codesandbox.io/s/compassionate-elbakyan-f7tun?file=/src/App.js

在此示例中,切换 darkMode 的状态会将 dark-mode 类名添加或删除到***容器。

import React,  useState  from "react";
import "./styles.css";

export default function App() 
  const [darkMode, setDarkMode] = useState(false);

  return (
    <div className=`App $darkMode && "dark-mode"`>
      <label>
        <input
          type="checkbox"
          checked=darkMode
          onChange=() => setDarkMode((darkMode) => !darkMode)
        />
        Dark Mode?
      </label>
      <h1>Hello CodeSandbox</h1>
    </div>
  );

如果darkMode 为真,并且存在dark-mode 类名,则将使用这些样式:

h1 
  padding: 0.5rem;
  border: 3px dotted red;


.dark-mode 
  background: black;
  color: white;


.dark-mode h1 
  border-color: aqua;

【讨论】:

【参考方案5】:

您必须创建 2 个组件

第一个:

import './App.dark.css'

const DarkApp =() =>
   //the app container

第二个:

import './App.light.css'

const LightApp =() =>
   //the app container

并创建 HOC 来像这样处理darkMode

const AppLayout = () =>
const [isDark , setIsDark] = useState(false);


return (
 <>
  
  isDark ? 
    <DarkApp /> :
      <LightApp />
  
 </>
 )

【讨论】:

【参考方案6】:

    在运行时使用更少的编译器:https://medium.com/@mzohaib.qc/ant-design-dynamic-runtime-theme-1f9a1a030ba0

    将更少的代码导入包装器https://github.com/less/less.js/issues/3232

.any-scope 
    @import url('~antd/dist/antd.dark.less');

【讨论】:

如何使用 create react app 做到这一点? 在运行时编译更少的性能并不高。有人尝试了很多方法,发现最高效的方法是使用 cssvars:github.com/ant-design/ant-design/issues/…

以上是关于Ant design v4中如何动态切换主题?的主要内容,如果未能解决你的问题,请参考以下文章

ant-design实现主题暗黑主题 和 亮色主题的 切换(实现网站黑白皮肤)

Vue Ant Design Pro 中定制主题

如何在 Next.js 中使用自定义主题配置 Ant Design 并支持 CSS 模块功能

如何使用 CodeSandbox 在 LESS 中为 Ant Design (React) 创建自定义主题?

Ant Design Pro V5 包含演示效果创建方法

ant-design-vue 2中定制主题的方式