【问题标题】:How to switch between themes in Ant design v4 dynamically?Ant design v4中如何动态切换主题?
【发布时间】: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。试图解决这些。将添加评论。

标签: css reactjs less antd


【解决方案1】:

这是我现在使用的 -

PS-

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

创建一个名为“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';
      

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

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

      这是一个工作示例:

      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】:
          1. 在运行时使用更少的编译器:
            https://medium.com/@mzohaib.qc/ant-design-dynamic-runtime-theme-1f9a1a030ba0

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

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

          【讨论】:

          猜你喜欢
          • 2023-02-09
          • 2020-05-24
          • 1970-01-01
          • 2022-09-23
          • 2021-01-23
          • 2018-07-30
          • 1970-01-01
          • 1970-01-01
          • 2019-08-17
          相关资源
          最近更新 更多