Bagaimana untuk menyesuaikan tema dinamik dalam Reka Bentuk Semut? Mari bercakap tentang kaedah pelaksanaan

青灯夜游
Lepaskan: 2021-12-20 14:19:37
ke hadapan
3394 orang telah melayarinya

Bagaimana untuk menyesuaikan tema dinamik dalam Reka Bentuk Semut? Artikel ini memperkenalkan cara untuk menyesuaikan tema dan melaksanakan tema dinamik dalam Reka Bentuk Semut Saya harap ia akan membantu semua orang.

Bagaimana untuk menyesuaikan tema dinamik dalam Reka Bentuk Semut? Mari bercakap tentang kaedah pelaksanaan

1. Prakata

Hai semua, lama tidak berjumpa saya baru-baru ini menghadapi keperluan untuk tema dinamik dalam projek, jadi saya akan merekodkan pelaksanaannya proses. Artikel ini mungkin agak panjang, sila baca dengan sabar

2. Persediaan persekitaran

Untuk kemudahan, contoh dalam artikel ini menggunakan create-react-app caco craco-less pelaksanaan:

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

akan package.json > Cuma ubah suai npm-script dalam:

{
  scripts: {
    "start": "craco start"
  }
}
Salin selepas log masuk

By the way, tambahkan awalan craco.config.js:

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

module.exports = {
  plugins: [{ plugin: CracoLessPlugin }],
};
Salin selepas log masuk

Kemudian, tukar 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;
Salin selepas log masuk

Kemudian mulakan dan anda akan melihat antara muka berikut:

Bagaimana untuk menyesuaikan tema dinamik dalam Reka Bentuk Semut? Mari bercakap tentang kaedah pelaksanaan

Mengenai mengapa tiada gaya, anda boleh membaca artikel sebelumnya "Vite Boleh Puaskan anda? 》

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

Bagaimana untuk memperkenalkan tema?

Dalam Reka Bentuk Semut, terdapat banyak postur untuk memperkenalkan tema Mari kita susun secara ringkasnya di bawah.

1. Import fail gaya

Perkenalkan fail gaya terus ke App.js:

// App.js
import &#39;antd/dist/antd.css&#39;;
Salin selepas log masuk

Tetapi sejak If anda menggunakan craco-less, kemudian gunakan fail Ant Designless, tetapi apabila anda mengimport terus antd.less, anda akan mendapat ralat berikut:

Bagaimana untuk menyesuaikan tema dinamik dalam Reka Bentuk Semut? Mari bercakap tentang kaedah pelaksanaan

Menyelesaikan masalah ini sangat mudah, cuma buka lessOption dalam javascriptEnabled:

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

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

Kemudian anda boleh melihat antara muka berikut:

Bagaimana untuk menyesuaikan tema dinamik dalam Reka Bentuk Semut? Mari bercakap tentang kaedah pelaksanaan

【Cadangan berkaitan: "Aplikasi Ant Design Pro "]

Sudah tentu, anda juga boleh memilih untuk memperkenalkannya dalam App.less:

@import &#39;~antd/dist/antd.less&#39;;
Salin selepas log masuk

2. babel-plugin-import

Dalam artikel sebelum ini, saya menyebut cara menggunakan babel-plugin-import, dan langkah-langkah untuk menggunakannya dengan craco ialah yang sama, kecuali Anda perlu menambah konfigurasi yang sepadan dalam craco.config.js:

// craco.config.js

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

Dengan cara ini anda boleh memadamkan gaya yang diperkenalkan dalam App.js/App.less di atas.

4. Bagaimana untuk melaksanakan tema tersuai dan tema dinamik?

Dua kaedah di atas adalah cara yang paling biasa digunakan untuk memperkenalkan gaya Reka Bentuk Semut Berdasarkan kaedah di atas, kami akan menerangkan cara mengubah suai dan menulis ganti gaya asal.

Malah, anda boleh mendapati terdapat banyak fail gaya yang disediakan dalam 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
Salin selepas log masuk

antd.(dark|compact).less Kedua-dua fail tersebut masing-masing adalah gaya mod gelap dan padat, dan antd.variable.less fail Ia adalah fail yang hanya tersedia dalam versi terkini Reka Bentuk Semut Penggunaannya akan dibincangkan di bawah Selain daripada fail gaya .less, anda akan mendapati terdapat beberapa xxx-theme.js Jika anda membukanya, didapati bahawa sebenarnya terdapat nilai pembolehubah ​​​​untuk setiap tema Ambil dark-theme.js sebagai contoh:

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

Cara menggunakannya akan dibincangkan di bawah. Sekarang mari kita mulakan topik artikel ini: melaksanakan tema tersuai dan tema dinamik.

1. Tema tersuai

Jika anda ingin melaksanakan tema tersuai, ia adalah sangat mudah gaya override, contohnya, apabila menggunakan tema gelap, teruskan memperkenalkan fail gaya mod gelap Contohnya, jika anda ingin mengubah suai warna utama di bawah tema lalai, biasanya terdapat dua cara: dengan mengubah suai fail gaya. atau melalui . lessOption

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

@primary-color: green;
Salin selepas log masuk

Bagaimana untuk menyesuaikan tema dinamik dalam Reka Bentuk Semut? Mari bercakap tentang kaedah pelaksanaan

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

Bagaimana untuk menyesuaikan tema dinamik dalam Reka Bentuk Semut? Mari bercakap tentang kaedah pelaksanaan

Perlu dikatakan bahawa jika kedua-dua kaedah penyesuaian tema ini digunakan pada masa yang sama , ia hanya akan digunakan Jenis kandungan kedua ditetapkan melalui

. Jika anda bertanya kepada saya mengapa, maka saya akan memasukkan pelajaran tambahan modifyVars untuk menerangkan less


Kelas kurang kecil

Premise: Perkenalkan

dalam App.less dan tulis ganti antd.less (mengambil @primary-color yang dikonfigurasikan di atas sebagai contoh) green

menyediakan baris arahan yang membolehkan kami menggunakan perintah less untuk Terminal fail dilarikan sebagai .less: CSS

# 转义 less 文件
npx lessc ./src/App.less ./src/App.css --js
Salin selepas log masuk
Mari kita lihat apakah

dalam App.css itu: primary-color

.ant-btn-primary {
  border-color: green;
  background: green;
}
Salin selepas log masuk

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

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

在看下生成的 App.css 嘞:

.ant-btn-primary {
  border-color: cyan;
  background: cyan;
}
Salin selepas log masuk

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; }
}
Salin selepas log masuk

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

var parseTree = new ParseTree(root, imports);
Salin selepas log masuk

这一步是将 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;
  	}
  },
  // ...
]
Salin selepas log masuk

这样是不是可以理解了?就是 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;
}
Salin selepas log masuk

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

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

Bagaimana untuk menyesuaikan tema dinamik dalam Reka Bentuk Semut? Mari bercakap tentang kaedah pelaksanaan

就是这么简单,在使用 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;;
Salin selepas log masuk

Bagaimana untuk menyesuaikan tema dinamik dalam Reka Bentuk Semut? Mari bercakap tentang kaedah pelaksanaan

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

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

Bagaimana untuk menyesuaikan tema dinamik dalam Reka Bentuk Semut? Mari bercakap tentang kaedah pelaksanaan

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

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

Bagaimana untuk menyesuaikan tema dinamik dalam Reka Bentuk Semut? Mari bercakap tentang kaedah pelaksanaan

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

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

可以看到,通过这种方式来配置的颜色仅有上面六种,但如果你想 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;);
Salin selepas log masuk

所以他只是对这几种颜色进行了特定处理,而对于其它的颜色(比如组件背景色)等并未作处理,但即使某些颜色的命名方式也符合这种规范,也不会奏效,毕竟 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);
	// ...
}
Salin selepas log masuk

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

Bagaimana untuk menyesuaikan tema dinamik dalam Reka Bentuk Semut? Mari bercakap tentang kaedah pelaksanaan

1Bagaimana untuk menyesuaikan tema dinamik dalam Reka Bentuk Semut? Mari bercakap tentang kaedah pelaksanaan

具体内容可以看上面截图,我就不再赘述,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;;
  }
}
Salin selepas log masuk

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

Bagaimana untuk menyesuaikan tema dinamik dalam Reka Bentuk Semut? Mari bercakap tentang kaedah pelaksanaan

如何实现修改 :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]);
  });
};
Salin selepas log masuk

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

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

如果你去看 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;
  // ...
},
Salin selepas log masuk

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

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

Atas ialah kandungan terperinci Bagaimana untuk menyesuaikan tema dinamik dalam Reka Bentuk Semut? Mari bercakap tentang kaedah pelaksanaan. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Label berkaitan:
sumber:juejin.cn
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan