搜尋
首頁web前端前端問答Ant Design中如何自訂動態主題?聊聊實現方法

Ant Design中如何自訂動態主題?這篇文章給介紹一下在 Ant Design 中客製化主題和實現動態主題的方法,希望對大家有幫助!

Ant Design中如何自訂動態主題?聊聊實現方法

一、前言

Hey 各位,好久不見,最近在專案中遇到了動態主題的需求,所以就順手記錄實現過程。本文篇幅可能有些長,請耐心觀看

二、環境準備

為了方便,本文中範例使用了create-react-app caco craco-less 實作:

# 创建项目
create-react-app demo
# 安装必要依赖
yarn add antd # 记得要装最新版
yarn add -D @craco/craco craco-less babel-plugin-import

package.json 中的npm-script 修改一下即可:

{
  scripts: {
    "start": "craco start"
  }
}

順便新增下初始的craco. config.js

const CracoLessPlugin = require('craco-less');

module.exports = {
  plugins: [{ plugin: CracoLessPlugin }],
};

然後,改一下App.js

import { useState } from 'react';
import { Avatar, Card, Button, Space, Switch } from 'antd';

function App() {
  const [theme, setTheme] = useState('light');
  const checked = theme === 'light';

  const handleThemeChange = (checked) => {
    setTheme(checked ? 'light' : 'dark');
  };

  return (
    <div className="App">
      <Card title={<Avatar size="large" src={logo} />}>
        <Space>
          <Switch
            checked={checked}
            checkedChildren="亮"
            unCheckedChildren="暗"
            onChange={handleThemeChange}
          />
          <Button type="primary">动态主题</Button>
        </Space>
      </Card>
    </div>
  );
}

export default App;

然後啟動就可以看到如下介面:

Ant Design中如何自訂動態主題?聊聊實現方法

至於為何沒有樣式,各位可以看之前的文章《Vite 能滿足你嗎? 》

https://mp.weixin.qq.com/s/68E7CBXrhAd4u5kAt99nOA

三、如何引入主題?

Ant Design 中,有許多種姿勢引入主題,以下先來簡單的整理一下。

1. 引入樣式檔

直接在 App.js 中引入樣式檔:

// App.js
import &#39;antd/dist/antd.css&#39;;

但既然使用了craco-less 那就使用Ant Designless 檔案吧,但是當你直接引入antd.less 時,會得到以下錯誤:

Ant Design中如何自訂動態主題?聊聊實現方法

解決這個問題很簡單,只需要在lessOption 中將javascriptEnabled 開啟即可:

const CracoLessPlugin = require(&#39;craco-less&#39;);

module.exports = {
  plugins: [
    {
      plugin: CracoLessPlugin,
      options: {
        lessLoaderOptions: {
          lessOptions: {
            javascriptEnabled: true,
          },
        },
      },
    },
  ],
};

然後就可以看到如下介面:

Ant Design中如何自訂動態主題?聊聊實現方法

#【相關推薦:《Ant Design Pro應用》】

當然你也可以選擇在App.less 中引入:

@import &#39;~antd/dist/antd.less&#39;;

2. babel-plugin-import

之前的文章中說過如何使用babel-plugin-import,配合craco 的使用步驟是一樣的,只不過需要在craco.config .js 中加入對應的配置即可:

// craco.config.js

module.exports = {
  babel: {
    plugins: [
      [&#39;import&#39;, { libraryName: &#39;antd&#39;, libraryDirectory: &#39;es&#39;, style: true }],
    ],
  },
  // ...
};

這樣就可以刪掉上面在App.js/App.less 引入的樣式了。

四、如何實現客製化主題和動態主題?

上面兩種方式就是最常用的引入 Ant Design 樣式的方式,下面講基於上面的方式來講解如何修改覆蓋原有樣式。

其實可以發現在antd/dist 中提供了很多種樣式檔:

├── antd.compact.less
├── antd.dark.less
├── antd.less
├── antd.variable.less
├── compact-theme.js
├── dark-theme.js
├── default-theme.js
├── theme.js
└── variable-theme.js

antd.(dark|compact).less 兩個文件分別是黑暗和緊湊模式的樣式,而antd.variable.less 文件則是最新版Ant Design 才有的文件,它有什麼用下面會說到,除了.less 樣式文件之外各位會發現還有幾個xxx-theme.js 文件,如果你打開會發現裡面其實都是各個主題的變數值,以dark-theme.js 為例:

const darkThemeSingle = {
  "theme": "dark",
  "popover-background": "#1f1f1f",
  "popover-customize-border-color": "#3a3a3a",
  "body-background": "@black",
  "component-background": "#141414",
  // ...
};

如何使用下面會講,現在就開始本文的主題:實作客製化主題和動態主題。

1. 客製化主題

如果你想實作客製化主題,那很簡單,簡單來說就是樣式覆蓋,例如使用黑暗主題就直接引入黑暗模式的樣式文件,例如在預設主題下想修改主色調一般有兩種方式:透過修改樣式文件或透過lessOption

// 1. 通过修改样式文件
// App.less
@import  &#39;~antd/dist/antd.less&#39;;

@primary-color: green;

Ant Design中如何自訂動態主題?聊聊實現方法

// 2. 通过 lessOptions
// craco.config.js
module.exports = {
  // ...
  plugins: [
    {
      plugin: CracoLessPlugin,
      options: {
        lessLoaderOptions: {
          lessOptions: {
            modifyVars: {
              &#39;primary-color&#39;: &#39;cyan&#39;,
            },
            javascriptEnabled: true,
          },
        },
      },
    },
  ],
};

Ant Design中如何自訂動態主題?聊聊實現方法

需要說一下,如果同時使用了這兩種自訂主題的方式,則只會應用第二種通過modifyVars 設定的內容。如果你問我為啥,那我就額外插一節less 講解的課吧


Less 小課堂

前提:在App.less 中引入antd.less 並且覆蓋@primary-color(以上面配置的green 為例)

less 提供了命令列讓我們可以透過Terminal 指令將.less 檔案轉義為 CSS

# 转义 less 文件
npx lessc ./src/App.less ./src/App.css --js

讓我們來看看App.css 中的primary-color 是什麼:

.ant-btn-primary {
  border-color: green;
  background: green;
}

可以看到 primary-color 设为 green 生效了,我们再加上 modifyVars 看下呢?

npx lessc ./src/App.less ./src/App.css --js --modify-var="primary-color: cyan"

在看下生成的 App.css 嘞:

.ant-btn-primary {
  border-color: cyan;
  background: cyan;
}

Wow~竟然和我们本地开发时一样替换成了 modifyVars 中的内容!这又是为啥呢?

我们进入 node_modules/.bin/lessc 文件,在 parseLessFileconsole 一下 dataoptions 内容会得到源文件字符串和命令行中的一些配置,在此我们会得到:

# data
@import &#39;antd/dist/antd.less&#39;;

@primary-color: green;

.App {
  text-align: center;
}

# options
{
  javascriptEnabled: true,
  modifyVars: { &#39;primary-color&#39;: &#39;cyan&#39; }
}

随后我们再进入 node_modules/less/lib/less/render.js 文件,进入 render 方法可以看到:

var parseTree = new ParseTree(root, imports);

这一步是将 less 转为 AST,让我们来看一下转换后的 AST

console.log(parseTree.root.rules);
// Rules AST
[
  // ...
  Node {
  	name: &#39;@primary-color&#39;,
  	value: Node {
  		value: &#39;green&#39;
  	}
  },
  Node {
  	name: &#39;@primary-color&#39;,
  	value: Node {
  		value: &#39;cyan&#39;
  	}
  },
  // ...
]

这样是不是可以理解了?就是 modifyVars 中的变量覆盖了样式文件中的变量。下课!


再回到定制主题的相关内容,现在说下如何使用上面说到的 darkSingleTheme,我们可以看下 theme.js 的内容:

function getThemeVariables(options = {}) {
  let themeVar = {
    &#39;hack&#39;: `true;@import "${require.resolve(&#39;antd/lib/style/color/colorPalette.less&#39;)}";`,
    ...defaultTheme
  };
  if(options.dark) {
    themeVar = {
      ...themeVar,
      ...darkThemeSingle
    }
  }
  if(options.compact){
    themeVar = {
      ...themeVar,
      ...compactThemeSingle
    }
  }
  return themeVar;
}

可以看到,如果我们在使用 getThemeVariables 时将 darkcompact 设为 true 就能应用上对应的样式,我们来试下:

// craco.config.js
module.exports = {
  // ...
  plugins: [
    {
      plugin: CracoLessPlugin,
      options: {
        lessLoaderOptions: {
          lessOptions: {
            modifyVars: {
              ...getThemeVariables({
                dark: true,
              }),
            },
            javascriptEnabled: true,
          },
        },
      },
    },
  ],
};

Ant Design中如何自訂動態主題?聊聊實現方法

就是这么简单,在使用 getThemeVariables 时也可以搭配前面所说的 modifyVars 来覆盖样式。这就是常用的定制主题的方式,就是之前所说的 覆盖变量,总结一下这两种方式:

  • 引入主题样式文件并覆盖对应 Less 变量;

  • 使用 getThemeVariables 引入对应主题,通过 modifyVars 覆盖变量值;

2. 动态主题

到现在 Ant Design 文档都没有出切换亮/暗模式的功能,但在文档中却有提到相应功能。在本文中主要介绍3种方式,其中一种就是官方出的 动态主题(实验性)

I. 动态切换样式文件

切换样式文件,这应该是最容易想到的一个方案,Ant Design 本来就提供了例如 default/dark/compact 主题的样式,我们只需要将这些文件保存在我们的项目中,按需切换即可,这个方案不赘述,实现起来也十分简单。

II. ConfigProvider

ConfigProviderAnt Design 提供的一个实验性的动态主题方案,使用很简单,在入口 .less 文件中引入 variable.less 文件,然后在 ConfigProvider 中复写对应变量,具体使用如下:

// App.less
@import &#39;antd/dist/antd.variable.less&#39;;

Ant Design中如何自訂動態主題?聊聊實現方法

默认样式与 primary 一样,然后我们使用 ConfigProvider 修改主题色(还是以 primaryColor 为例):

// App.js
// 增加下面一行
ConfigProvider.config({ theme: { primaryColor: &#39;aquamarine&#39; } });

Ant Design中如何自訂動態主題?聊聊實現方法

动态切换我们与上面使用方式一致:

// App.js
ConfigProvider.config({
  theme: {
    primaryColor: checked ? &#39;aquamarine&#39; : &#39;darkgreen&#39;,
  },
});

Ant Design中如何自訂動態主題?聊聊實現方法

这么方便,这么好用,他有什么不足之处么?有,但只要你不介意其实问题不大。通过 ConfigProvider 可以配置的颜色很有限:

// node_modules/antd/es/config-provider/context.d.ts
interface Theme {
    primaryColor?: string;
    infoColor?: string;
    successColor?: string;
    processingColor?: string;
    errorColor?: string;
    warningColor?: string;
}

可以看到,通过这种方式来配置的颜色仅有上面六种,但如果你想 extends Theme 来添加其他字段,那不好意思,行不通,再来看下它是如何处理这几种颜色的:

/**
 * @param {string} colorVal
 * @param {string} type
 */
var fillColor = function fillColor(colorVal, type) {
  var baseColor = new TinyColor(colorVal);
  var colorPalettes = generate(baseColor.toRgbString());
  variables["".concat(type, "-color")] = formatColor(baseColor);
  variables["".concat(type, "-color-disabled")] = colorPalettes[1];
  variables["".concat(type, "-color-hover")] = colorPalettes[4];
  variables["".concat(type, "-color-active")] = colorPalettes[7];
  variables["".concat(type, "-color-outline")] = baseColor.clone().setAlpha(0.2).toRgbString();
  variables["".concat(type, "-color-deprecated-bg")] = colorPalettes[1];
  variables["".concat(type, "-color-deprecated-border")] = colorPalettes[3];
};

// 使用如下
fillColor(theme.successColor, &#39;success&#39;);

所以他只是对这几种颜色进行了特定处理,而对于其它的颜色(比如组件背景色)等并未作处理,但即使某些颜色的命名方式也符合这种规范,也不会奏效,毕竟 Ant Design 使用了 if (theme.successColor) 这种方式来条件修改这些颜色。

III. CSS Variables

我打算在这一部分来介绍 II. ConfigProviderantd.variable.less 的内容,因为这个方法与 Ant Design 提供的 ConfigProvider 本质上有些类似:通过 CSS Variables 来修改全局的颜色。我们打开对应文件来简单看下内容:

// node_modules/antd/lib/style/themes/variable.less

html {
  @base-primary: @blue-6;
  
  --@{ant-prefix}-primary-color: @base-primary;
  --@{ant-prefix}-primary-color-hover: color(~`colorPalette(&#39;@{base-primary}&#39;, 5) `);
  --@{ant-prefix}-primary-color-active: color(~`colorPalette(&#39;@{base-primary}&#39;, 7) `);
  --@{ant-prefix}-primary-color-outline: fade(@base-primary, @outline-fade);
	// ...
}

上面的代码中涉及了 less 中几个比较基本的语法:Variable InterpolationEscaping

Ant Design中如何自訂動態主題?聊聊實現方法

1Ant Design中如何自訂動態主題?聊聊實現方法

具体内容可以看上面截图,我就不再赘述,Ant Design 就通过这种方式实现了动态主题,将 color 值设置为可变的 CSS Variables。既然 ConfigProvider 可变的 color 有限,那我们就自己来定义这些颜色吧~这种方式实现起来比较复杂,但是可自定义性就无限可能了

// App.less
:root {
  --main-color: green;
}

.ant-btn {
  &.ant-btn-primary {
    border-color: ~&#39;var(--main-color)&#39;;
    background: ~&#39;var(--main-color)&#39;;
  }
}

看一下通过这种方式实现的效果:

Ant Design中如何自訂動態主題?聊聊實現方法

如何实现修改 :root 中的样式呢?具体 Ant Design 的实现各位可以看 node_modules/antd/es/config-provider/cssVariable.jsnode_modules/rc-util/es/Dom/dynamicCSS.js 两个文件,内容十分简单。我先写了一个简易版:

const dark = {
  &#39;--main-color&#39;: &#39;darkgray&#39;,
};

const light = {
  &#39;--main-color&#39;: &#39;green&#39;,
};

const themes = { dark, light };

const changeTheme = (theme) => {
  const nextTheme = themes[theme];
  Object.keys(nextTheme).forEach((key) => {
    document.documentElement.style.setProperty(key, nextTheme[key]);
  });
};

changeTheme 方法就是修改 :root 中样式的方法。

但为什么不直接在 App.less 中采用 @primary-color: ~'var(--main-color)' 的形式,非要重写组件样式呢?

如果你去看 Ant Design 中样式文件的源码你会发现其中用到了很多 function,比如 less 中的 fade 函数:

Set the absolute opacity of a color. Can be applied to colors whether they already have an opacity value or not.

来自 Less 官网:https://lesscss.org/functions/#color-operations-fade

如果我们采用刚才说的那种形式来修改 @primary-color 等样式,less 就会抛出异常:Argument cannot be evaluated to a color

// node_modules/less/lib/less/functions/color.js

// fade 方法
function fade (color, amount) {
  var hsl = toHSL(color);
  hsl.a = amount.value / 100;
  hsl.a = clamp(hsl.a);
  return hsla(color, hsl);
}

// toHSL 方法
function toHSL(color) {
    // 此处的 color.toHSL 函数是下面 color.js 中的 toHSL 函数
    if (color.toHSL) {
        return color.toHSL();
    }
    else {
        throw new Error(&#39;Argument cannot be evaluated to a color&#39;);
    }
}

// node_modules/less/lib/less/tree/color.js
function toHSL () {
  var r = this.rgb[0] / 255, g = this.rgb[1] / 255, b = this.rgb[2] / 255, a = this.alpha;
  // ...
},

这样就可以看出如果我们传给 fade 函数的不是一个准确的颜色值,在 color.js 中是获取不到 rgb[0] 等值的,所以在 less 编译过程中就会直接报错。

更多编程相关知识,请访问:编程视频!!

以上是Ant Design中如何自訂動態主題?聊聊實現方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:掘金社区。如有侵權,請聯絡admin@php.cn刪除
反應的局限性是什麼?反應的局限性是什麼?May 02, 2025 am 12:26 AM

Include:1)AsteeplearningCurvedUetoItsVasteCosystem,2)SeochallengesWithClient-SiderEndering,3)潛在的PersperformanceissuesInsuesInlArgeApplications,4)ComplexStateStateManagementAsappsgrow和5)TheneedtokeEedtokeEedtokeEppwithitsrapideDrapidevoltolution.thereedtokeEppectortorservolution.thereedthersrapidevolution.ththesefactorsshesssheou

React的學習曲線:新開發人員的挑戰React的學習曲線:新開發人員的挑戰May 02, 2025 am 12:24 AM

reactischallengingforbeginnersduetoitssteplearningcurveandparadigmshifttocoment oparchitecent.1)startwithofficialdocumentationforasolidFoundation.2)了解jsxandhowtoembedjavascriptwithinit.3)

為React中的動態列表生成穩定且獨特的鍵為React中的動態列表生成穩定且獨特的鍵May 02, 2025 am 12:22 AM

ThecorechallengeingeneratingstableanduniquekeysfordynamiclistsinReactisensuringconsistentidentifiersacrossre-rendersforefficientDOMupdates.1)Usenaturalkeyswhenpossible,astheyarereliableifuniqueandstable.2)Generatesynthetickeysbasedonmultipleattribute

JavaScript疲勞:與React及其工具保持最新JavaScript疲勞:與React及其工具保持最新May 02, 2025 am 12:19 AM

javascriptfatigueinrectismanagbaiblewithstrategiesLike just just in-timelearninganning and CuratedInformationsources.1)學習whatyouneedwhenyouneedit

使用USESTATE()掛鉤的測試組件使用USESTATE()掛鉤的測試組件May 02, 2025 am 12:13 AM

tateractComponents通過theusestatehook,使用jestandReaCtTestingLibraryToSigulationsimintionsandIntractions and verifyStateChangesInTheUI.1)underthecomponentAndComponentAndComponentAndConconentAndCheckInitialState.2)模擬useruseruserusertactionslikeclicksorformsorformsormissions.3)

React中的鑰匙:深入研究性能優化技術React中的鑰匙:深入研究性能優化技術May 01, 2025 am 12:25 AM

KeysinreactarecrucialforopTimizingPerformanceByingIneFefitedListupDates.1)useKeyStoIndentifyAndTrackListelements.2)避免使用ArrayIndi​​cesasKeystopreventperformansissues.3)ChooSestableIdentifierslikeIdentifierSlikeItem.idtomaintainAinainCommaintOnconMaintOmentStateAteanDimpperperFermerfermperfermerformperfermerformfermerformfermerformfermerment.ChosestopReventPerformissues.3)

反應中的鍵是什麼?反應中的鍵是什麼?May 01, 2025 am 12:25 AM

ReactKeySareUniqueIdentifiers usedwhenrenderingListstoimprovereConciliation效率。 1)heelPreactrackChangesInListItems,2)使用StableanDuniqueIdentifiersLikeItifiersLikeItemidSisRecumended,3)避免使用ArrayIndi​​cesaskeyindicesaskeystopreventopReventOpReventSissUseSuseSuseWithReRefers和4)

反應中獨特鍵的重要性:避免常見的陷阱反應中獨特鍵的重要性:避免常見的陷阱May 01, 2025 am 12:19 AM

獨特的keysarecrucialinreactforoptimizingRendering和MaintainingComponentStateTegrity.1)useanaturalAlaluniqueIdentifierFromyourDataiFabable.2)ifnonaturalalientedifierexistsistsists,generateauniqueKeyniqueKeyKeyLiquekeyperaliqeyAliqueLiqueAlighatiSaliqueLiberaryLlikikeuuId.3)deversearrayIndi​​ceSaskeyseSecialIndiceSeasseAsialIndiceAseAsialIndiceAsiall

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

SublimeText3 英文版

SublimeText3 英文版

推薦:為Win版本,支援程式碼提示!

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

將Eclipse與SAP NetWeaver應用伺服器整合。

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。