Jelajahi Sumber

高性能方案实现ant-design在运行时动态改变主题色(利用webpack-theme-color-replacer)

hz 6 tahun lalu
induk
melakukan
5e99cb1f95

+ 28 - 13
config/plugin.config.js

@@ -1,7 +1,8 @@
 // Change theme plugin
 
 import MergeLessPlugin from 'antd-pro-merge-less';
-import AntDesignThemePlugin from 'antd-theme-webpack-plugin';
+// import AntDesignThemePlugin from 'antd-theme-webpack-plugin';
+const ThemeColorReplacer = require('webpack-theme-color-replacer');
 import path from 'path';
 
 function getModulePackageName(module) {
@@ -39,18 +40,21 @@ export default config => {
         outFile,
       },
     ]);
-
-    config.plugin('ant-design-theme').use(AntDesignThemePlugin, [
-      {
-        antDir: path.join(__dirname, '../node_modules/antd'),
-        stylesDir,
-        varFile: path.join(__dirname, '../node_modules/antd/lib/style/themes/default.less'),
-        mainLessFile: outFile, //     themeVariables: ['@primary-color'],
-        indexFileName: 'index.html',
-        generateOne: true,
-        lessUrl: 'https://gw.alipayobjects.com/os/lib/less.js/3.8.1/less.min.js',
-      },
-    ]);
+    config.plugin('webpack-theme-color-replacer').use(ThemeColorReplacer, [{
+      fileName: 'css/theme-colors.css',
+      matchColors: getAntdSerials('#1890ff'), // 主色系列
+    }]);
+    // config.plugin('ant-design-theme').use(AntDesignThemePlugin, [
+    //   {
+    //     antDir: path.join(__dirname, '../node_modules/antd'),
+    //     stylesDir,
+    //     varFile: path.join(__dirname, '../node_modules/antd/lib/style/themes/default.less'),
+    //     mainLessFile: outFile, //     themeVariables: ['@primary-color'],
+    //     indexFileName: 'index.html',
+    //     generateOne: true,
+    //     lessUrl: 'https://gw.alipayobjects.com/os/lib/less.js/3.8.1/less.min.js',
+    //   },
+    // ]);
   }
   // optimize chunks
   config.optimization
@@ -81,3 +85,14 @@ export default config => {
       },
     });
 };
+
+function getAntdSerials(color) {
+  const lightens = new Array(9).fill().map((t, i) => {
+    return ThemeColorReplacer.varyColor.lighten(color, i / 10);
+  });
+  // 此处为了简化,采用了darken。实际按color.less需求可以引入tinycolor, colorPalette变换得到颜色值
+  const darkens = new Array(6).fill().map((t, i) => {
+    return ThemeColorReplacer.varyColor.darken(color, i / 10);
+  });
+  return lightens.concat(darkens);
+}

+ 2 - 1
package.json

@@ -82,7 +82,8 @@
     "resize-observer-polyfill": "^1.5.1",
     "umi": "^2.4.4",
     "umi-plugin-react": "^1.7.2",
-    "umi-request": "^1.0.5"
+    "umi-request": "^1.0.5",
+    "webpack-theme-color-replacer": "^1.1.3"
   },
   "devDependencies": {
     "@types/history": "^4.7.2",

+ 27 - 0
src/components/SettingDrawer/themeColorClient.js

@@ -0,0 +1,27 @@
+const client = require('webpack-theme-color-replacer/client')
+
+export default {
+  primaryColor: '#1890ff',
+  getAntdSerials (color) {
+    // 淡化(即less的tint)
+    const lightens = new Array(9).fill().map((t, i) => {
+      return client.varyColor.lighten(color, i / 10)
+    })
+    // 此处为了简化,采用了darken。实际按color.less需求可以引入tinycolor, colorPalette变换得到颜色值
+    const darkens = new Array(6).fill().map((t, i) => {
+      return client.varyColor.darken(color, i / 10)
+    })
+    return lightens.concat(darkens)
+  },
+  changeColor (newColor) {
+    const lastColor = this.lastColor || this.primaryColor
+    const options = {
+      cssUrl: '/css/theme-colors.css', // hash模式下用相对路径
+      oldColors: this.getAntdSerials(lastColor), // current colors array. The same as `matchColors`
+      newColors: this.getAntdSerials(newColor || this.primaryColor) // new colors array, one-to-one corresponde with `oldColors`
+    }
+    const promise = client.changer.changeColor(options)
+    this.lastColor = lastColor
+    return promise
+  }
+}

+ 8 - 0
src/models/setting.js

@@ -1,6 +1,13 @@
 import { message } from 'antd';
 import defaultSettings from '../defaultSettings';
+import themeColorClient from '../components/SettingDrawer/themeColorClient'
 
+const updateTheme = newPrimaryColor => {
+  const hideMessage = message.loading('正在切换主题!', 0)
+  themeColorClient.changeColor(newPrimaryColor)
+    .finally(() => hideMessage())
+}
+/*
 let lessNodesAppended;
 const updateTheme = primaryColor => {
   // Don't compile less in production!
@@ -59,6 +66,7 @@ const updateTheme = primaryColor => {
     buildIt();
   }
 };
+*/
 
 const updateColorWeak = colorWeak => {
   document.body.className = colorWeak ? 'colorWeak' : '';