溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Ant Design中怎么定制動(dòng)態(tài)主題

發(fā)布時(shí)間:2021-12-20 14:34:37 來源:億速云 閱讀:187 作者:小新 欄目:web開發(fā)

小編給大家分享一下Ant Design中怎么定制動(dòng)態(tài)主題,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

環(huán)境準(zhǔn)備

為了方便,本文中示例使用了 create-react-app + caco + craco-less 實(shí)現(xiàn):

# 創(chuàng)建項(xiàng)目
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">動(dòng)態(tài)主題</Button>
        </Space>
      </Card>
    </div>
  );
}

export default App;

然后啟動(dòng)就可以看到如下界面:

Ant Design中怎么定制動(dòng)態(tài)主題

如何引入主題?

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

1. 引入樣式文件

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

// App.js
import 'antd/dist/antd.css';

但既然使用了 craco-less 那就使用 Ant Designless 文件吧,但是當(dāng)你直接引入 antd.less 時(shí),會得到如下錯(cuò)誤:

Ant Design中怎么定制動(dòng)態(tài)主題

解決這個(gè)問題很簡單,只需要在 lessOption 中將 javascriptEnabled 打開即可:

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

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

然后就可以看到如下界面:

Ant Design中怎么定制動(dòng)態(tài)主題

當(dāng)然你也可以選擇在 App.less 中引入:

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

2. babel-plugin-import

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

// craco.config.js

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

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

如何實(shí)現(xiàn)定制主題和動(dòng)態(tài)主題?

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

其實(shí)可以發(fā)現(xiàn)在 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 兩個(gè)文件分別是黑暗和緊湊模式的樣式,而 antd.variable.less 文件則是最新版 Ant Design 才有的文件,它有什么用下面會說到,除了 .less 樣式文件之外各位會發(fā)現(xiàn)還有幾個(gè) xxx-theme.js 文件,如果你打開會發(fā)現(xiàn)里面其實(shí)都是各個(gè)主題的變量值,以 dark-theme.js 為例:

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

如何使用下面會講,現(xiàn)在就開始本文的主題:實(shí)現(xiàn)定制主題和動(dòng)態(tài)主題。

1. 定制主題

如果你想實(shí)現(xiàn)定制主題,那很簡單,簡單來說就是 樣式覆蓋,比如使用黑暗主題就直接引入黑暗模式的樣式文件,比如在默認(rèn)主題下想修改主色調(diào)一般有兩種方式:通過修改樣式文件或通過 lessOption。

// 1. 通過修改樣式文件
// App.less
@import  '~antd/dist/antd.less';

@primary-color: green;

Ant Design中怎么定制動(dòng)態(tài)主題

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

Ant Design中怎么定制動(dòng)態(tài)主題

需要說一下,如果同時(shí)使用了這兩種定制主題的方式,則只會應(yīng)用第二種通過 modifyVars 設(shè)置的內(nèi)容。如果你問我為啥,那我就額外插一節(jié) less 講解的課吧


Less 小課堂

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

less 提供了命令行讓我們可以通過 Terminal 命令將 .less 文件轉(zhuǎn)義為 CSS

# 轉(zhuǎn)義 less 文件
npx lessc ./src/App.less ./src/App.css --js

讓我們看一下 App.css 中的 primary-color 是什么:

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

可以看到 primary-color 設(shè)為 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~竟然和我們本地開發(fā)時(shí)一樣替換成了 modifyVars 中的內(nèi)容!這又是為啥呢?

我們進(jìn)入 node_modules/.bin/lessc 文件,在 parseLessFileconsole 一下 dataoptions 內(nèi)容會得到源文件字符串和命令行中的一些配置,在此我們會得到:

# data
@import 'antd/dist/antd.less';

@primary-color: green;

.App {
  text-align: center;
}

# options
{
  javascriptEnabled: true,
  modifyVars: { 'primary-color': 'cyan' }
}

隨后我們再進(jìn)入 node_modules/less/lib/less/render.js 文件,進(jìn)入 render 方法可以看到:

var parseTree = new ParseTree(root, imports);

這一步是將 less 轉(zhuǎn)為 AST,讓我們來看一下轉(zhuǎn)換后的 AST

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

這樣是不是可以理解了?就是 modifyVars 中的變量覆蓋了樣式文件中的變量。下課!


再回到定制主題的相關(guān)內(nèi)容,現(xiàn)在說下如何使用上面說到的 darkSingleTheme,我們可以看下 theme.js 的內(nèi)容:

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

可以看到,如果我們在使用 getThemeVariables 時(shí)將 darkcompact 設(shè)為 true 就能應(yīng)用上對應(yīng)的樣式,我們來試下:

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

Ant Design中怎么定制動(dòng)態(tài)主題

就是這么簡單,在使用 getThemeVariables 時(shí)也可以搭配前面所說的 modifyVars 來覆蓋樣式。這就是常用的定制主題的方式,就是之前所說的 覆蓋變量,總結(jié)一下這兩種方式:

  • 引入主題樣式文件并覆蓋對應(yīng) Less 變量;

  • 使用 getThemeVariables 引入對應(yīng)主題,通過 modifyVars 覆蓋變量值;

2. 動(dòng)態(tài)主題

到現(xiàn)在 Ant Design 文檔都沒有出切換亮/暗模式的功能,但在文檔中卻有提到相應(yīng)功能。在本文中主要介紹3種方式,其中一種就是官方出的 動(dòng)態(tài)主題(實(shí)驗(yàn)性)

I. 動(dòng)態(tài)切換樣式文件

切換樣式文件,這應(yīng)該是最容易想到的一個(gè)方案,Ant Design 本來就提供了例如 default/dark/compact 主題的樣式,我們只需要將這些文件保存在我們的項(xiàng)目中,按需切換即可,這個(gè)方案不贅述,實(shí)現(xiàn)起來也十分簡單。

II. ConfigProvider

ConfigProviderAnt Design 提供的一個(gè)實(shí)驗(yàn)性的動(dòng)態(tài)主題方案,使用很簡單,在入口 .less 文件中引入 variable.less 文件,然后在 ConfigProvider 中復(fù)寫對應(yīng)變量,具體使用如下:

// App.less
@import 'antd/dist/antd.variable.less';

Ant Design中怎么定制動(dòng)態(tài)主題

默認(rèn)樣式與 primary 一樣,然后我們使用 ConfigProvider 修改主題色(還是以 primaryColor 為例):

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

Ant Design中怎么定制動(dòng)態(tài)主題

動(dòng)態(tài)切換我們與上面使用方式一致:

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

Ant Design中怎么定制動(dòng)態(tài)主題

這么方便,這么好用,他有什么不足之處么?有,但只要你不介意其實(shí)問題不大。通過 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, 'success');

所以他只是對這幾種顏色進(jìn)行了特定處理,而對于其它的顏色(比如組件背景色)等并未作處理,但即使某些顏色的命名方式也符合這種規(guī)范,也不會奏效,畢竟 Ant Design 使用了 if (theme.successColor) 這種方式來?xiàng)l件修改這些顏色。

III. CSS Variables

我打算在這一部分來介紹 II. ConfigProviderantd.variable.less 的內(nèi)容,因?yàn)檫@個(gè)方法與 Ant Design 提供的 ConfigProvider 本質(zhì)上有些類似:通過 CSS Variables 來修改全局的顏色。我們打開對應(yīng)文件來簡單看下內(nèi)容:

// 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('@{base-primary}', 5) `);
  --@{ant-prefix}-primary-color-active: color(~`colorPalette('@{base-primary}', 7) `);
  --@{ant-prefix}-primary-color-outline: fade(@base-primary, @outline-fade);
	// ...
}

上面的代碼中涉及了 less 中幾個(gè)比較基本的語法:Variable InterpolationEscaping。

Ant Design中怎么定制動(dòng)態(tài)主題

Ant Design中怎么定制動(dòng)態(tài)主題

具體內(nèi)容可以看上面截圖,我就不再贅述,Ant Design 就通過這種方式實(shí)現(xiàn)了動(dòng)態(tài)主題,將 color 值設(shè)置為可變的 CSS Variables。既然 ConfigProvider 可變的 color 有限,那我們就自己來定義這些顏色吧~這種方式實(shí)現(xiàn)起來比較復(fù)雜,但是可自定義性就無限可能了

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

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

看一下通過這種方式實(shí)現(xiàn)的效果:

Ant Design中怎么定制動(dòng)態(tài)主題

如何實(shí)現(xiàn)修改 :root 中的樣式呢?具體 Ant Design 的實(shí)現(xiàn)各位可以看 node_modules/antd/es/config-provider/cssVariable.jsnode_modules/rc-util/es/Dom/dynamicCSS.js 兩個(gè)文件,內(nèi)容十分簡單。我先寫了一個(gè)簡易版:

const dark = {
  '--main-color': 'darkgray',
};

const light = {
  '--main-color': 'green',
};

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 中樣式文件的源碼你會發(fā)現(xiàn)其中用到了很多 function,比如 less 中的 fade 函數(shù):

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

來自 Less 官網(wǎng):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 函數(shù)是下面 color.js 中的 toHSL 函數(shù)
    if (color.toHSL) {
        return color.toHSL();
    }
    else {
        throw new Error('Argument cannot be evaluated to a color');
    }
}

// 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 函數(shù)的不是一個(gè)準(zhǔn)確的顏色值,在 color.js 中是獲取不到 rgb[0] 等值的,所以在 less 編譯過程中就會直接報(bào)錯(cuò)。

以上是“Ant Design中怎么定制動(dòng)態(tài)主題”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI