您好,登錄后才能下訂單哦!
小編給大家分享一下Ant Design中怎么定制動態主題,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
為了方便,本文中示例使用了 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 中,有很多種姿勢引入主題,下面先來簡單的整理一下。
1. 引入樣式文件
直接在 App.js
中引入樣式文件:
// App.js import 'antd/dist/antd.css';
但既然使用了 craco-less
那就使用 Ant Design 的 less
文件吧,但是當你直接引入 antd.less
時,會得到如下錯誤:
解決這個問題很簡單,只需要在 lessOption
中將 javascriptEnabled
打開即可:
const CracoLessPlugin = require('craco-less'); module.exports = { plugins: [ { plugin: CracoLessPlugin, options: { lessLoaderOptions: { lessOptions: { javascriptEnabled: true, }, }, }, }, ], };
然后就可以看到如下界面:
當然你也可以選擇在 App.less
中引入:
@import '~antd/dist/antd.less';
2. babel-plugin-import
之前的文章中說過如何使用 babel-plugin-import
,配合 craco
的使用步驟是一樣的,只不過需要在 craco.config.js
中添加對應的配置即可:
// craco.config.js module.exports = { babel: { plugins: [ ['import', { libraryName: 'antd', libraryDirectory: 'es', 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 '~antd/dist/antd.less'; @primary-color: green;
// 2. 通過 lessOptions // craco.config.js module.exports = { // ... plugins: [ { plugin: CracoLessPlugin, options: { lessLoaderOptions: { lessOptions: { modifyVars: { 'primary-color': 'cyan', }, javascriptEnabled: true, }, }, }, }, ], };
需要說一下,如果同時使用了這兩種定制主題的方式,則只會應用第二種通過 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
文件,在 parseLessFile
中 console
一下 data
和 options
內容會得到源文件字符串和命令行中的一些配置,在此我們會得到:
# data @import 'antd/dist/antd.less'; @primary-color: green; .App { text-align: center; } # options { javascriptEnabled: true, modifyVars: { 'primary-color': 'cyan' } }
隨后我們再進入 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: '@primary-color', value: Node { value: 'green' } }, Node { name: '@primary-color', value: Node { value: 'cyan' } }, // ... ]
這樣是不是可以理解了?就是 modifyVars
中的變量覆蓋了樣式文件中的變量。下課!
再回到定制主題的相關內容,現在說下如何使用上面說到的 darkSingleTheme
,我們可以看下 theme.js
的內容:
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
時將 dark
或 compact
設為 true
就能應用上對應的樣式,我們來試下:
// craco.config.js module.exports = { // ... plugins: [ { plugin: CracoLessPlugin, options: { lessLoaderOptions: { lessOptions: { modifyVars: { ...getThemeVariables({ dark: true, }), }, javascriptEnabled: true, }, }, }, }, ], };
就是這么簡單,在使用 getThemeVariables
時也可以搭配前面所說的 modifyVars
來覆蓋樣式。這就是常用的定制主題的方式,就是之前所說的 覆蓋變量,總結一下這兩種方式:
引入主題樣式文件并覆蓋對應 Less
變量;
使用 getThemeVariables
引入對應主題,通過 modifyVars
覆蓋變量值;
2. 動態主題
到現在 Ant Design 文檔都沒有出切換亮/暗模式的功能,但在文檔中卻有提到相應功能。在本文中主要介紹3種方式,其中一種就是官方出的 動態主題(實驗性)。
I. 動態切換樣式文件
切換樣式文件,這應該是最容易想到的一個方案,Ant Design
本來就提供了例如 default/dark/compact
主題的樣式,我們只需要將這些文件保存在我們的項目中,按需切換即可,這個方案不贅述,實現起來也十分簡單。
II. ConfigProvider
ConfigProvider
是 Ant Design
提供的一個實驗性的動態主題方案,使用很簡單,在入口 .less
文件中引入 variable.less
文件,然后在 ConfigProvider
中復寫對應變量,具體使用如下:
// App.less @import 'antd/dist/antd.variable.less';
默認樣式與 primary
一樣,然后我們使用 ConfigProvider
修改主題色(還是以 primaryColor
為例):
// App.js // 增加下面一行 ConfigProvider.config({ theme: { primaryColor: 'aquamarine' } });
動態切換我們與上面使用方式一致:
// App.js ConfigProvider.config({ theme: { primaryColor: checked ? 'aquamarine' : 'darkgreen', }, });
這么方便,這么好用,他有什么不足之處么?有,但只要你不介意其實問題不大。通過 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');
所以他只是對這幾種顏色進行了特定處理,而對于其它的顏色(比如組件背景色)等并未作處理,但即使某些顏色的命名方式也符合這種規范,也不會奏效,畢竟 Ant Design
使用了 if (theme.successColor)
這種方式來條件修改這些顏色。
III. CSS Variables
我打算在這一部分來介紹 II. ConfigProvider 中 antd.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('@{base-primary}', 5) `); --@{ant-prefix}-primary-color-active: color(~`colorPalette('@{base-primary}', 7) `); --@{ant-prefix}-primary-color-outline: fade(@base-primary, @outline-fade); // ... }
上面的代碼中涉及了 less
中幾個比較基本的語法:Variable Interpolation 和 Escaping。
具體內容可以看上面截圖,我就不再贅述,Ant Design
就通過這種方式實現了動態主題,將 color
值設置為可變的 CSS Variables
。既然 ConfigProvider
可變的 color
有限,那我們就自己來定義這些顏色吧~這種方式實現起來比較復雜,但是可自定義性就無限可能了
// App.less :root { --main-color: green; } .ant-btn { &.ant-btn-primary { border-color: ~'var(--main-color)'; background: ~'var(--main-color)'; } }
看一下通過這種方式實現的效果:
如何實現修改 :root
中的樣式呢?具體 Ant Design
的實現各位可以看 node_modules/antd/es/config-provider/cssVariable.js
和 node_modules/rc-util/es/Dom/dynamicCSS.js
兩個文件,內容十分簡單。我先寫了一個簡易版:
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
中樣式文件的源碼你會發現其中用到了很多 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('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
函數的不是一個準確的顏色值,在 color.js
中是獲取不到 rgb[0]
等值的,所以在 less
編譯過程中就會直接報錯。
以上是“Ant Design中怎么定制動態主題”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。