Forráskód Böngészése

Merge pull request #4289 from hzsrc/master

高性能方案实现ant-design在运行时动态改变主题色(利用webpack-theme-color-replacer)
陈帅 6 éve
szülő
commit
3916692c6d

+ 50 - 19
config/plugin.config.ts

@@ -1,8 +1,10 @@
 // Change theme plugin
 
-import MergeLessPlugin from 'antd-pro-merge-less';
-import AntDesignThemePlugin from 'antd-theme-webpack-plugin';
+// import MergeLessPlugin from 'antd-pro-merge-less';
+// import AntDesignThemePlugin from 'antd-theme-webpack-plugin';
+import ThemeColorReplacer from 'webpack-theme-color-replacer';
 import path from 'path';
+import generate from '@ant-design/colors/lib/generate';
 
 function getModulePackageName(module: { context: string }) {
   if (!module.context) return null;
@@ -30,27 +32,45 @@ export default (config: any) => {
     process.env.NODE_ENV !== 'production'
   ) {
     // 将所有 less 合并为一个供 themePlugin使用
-    const outFile = path.join(__dirname, '../.temp/ant-design-pro.less');
-    const stylesDir = path.join(__dirname, '../src/');
+    // const outFile = path.join(__dirname, '../.temp/ant-design-pro.less');
+    // const stylesDir = path.join(__dirname, '../src/');
 
-    config.plugin('merge-less').use(MergeLessPlugin, [
+    // config.plugin('merge-less').use(MergeLessPlugin, [
+    //   {
+    //     stylesDir,
+    //     outFile,
+    //   },
+    // ]);
+    config.plugin('webpack-theme-color-replacer').use(ThemeColorReplacer, [
       {
-        stylesDir,
-        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',
+        fileName: 'css/theme-colors.css',
+        matchColors: getAntdSerials('#1890ff'), // 主色系列
+        // 改变样式选择器,解决样式覆盖问题
+        changeSelector(selector: string): string {
+          switch (selector) {
+            case '.ant-calendar-today .ant-calendar-date':
+              return ':not(.ant-calendar-selected-date)' + selector;
+            case '.ant-btn:focus,.ant-btn:hover':
+              return '.ant-btn:focus:not(.ant-btn-primary),.ant-btn:hover:not(.ant-btn-primary)';
+            case '.ant-btn.active,.ant-btn:active':
+              return '.ant-btn.active:not(.ant-btn-primary),.ant-btn:active:not(.ant-btn-primary)';
+            default:
+              return selector;
+          }
+        },
       },
     ]);
+    // 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
@@ -82,3 +102,14 @@ export default (config: any) => {
       },
     });
 };
+
+const getAntdSerials = (color: string) => {
+  const lightNum = 9;
+  const devide10 = 10;
+  // 淡化(即less的tint)
+  const lightens = new Array(lightNum).fill().map((t, i) => {
+    return ThemeColorReplacer.varyColor.lighten(color, i / devide10);
+  });
+  const colorPalettes = generate(color);
+  return lightens.concat(colorPalettes);
+}

+ 4 - 3
package.json

@@ -92,7 +92,7 @@
     "@types/react-document-title": "^2.0.3",
     "@types/react-dom": "^16.8.4",
     "antd-pro-merge-less": "^1.0.0",
-    "antd-theme-webpack-plugin": "^1.2.0",
+    "@ant-design/colors": "^3.1.0",
     "babel-eslint": "^10.0.1",
     "chalk": "^2.4.2",
     "check-prettier": "^1.0.3",
@@ -131,7 +131,8 @@
     "tslint": "^5.17.0",
     "tslint-config-prettier": "^1.18.0",
     "tslint-eslint-rules": "^5.4.0",
-    "tslint-react": "^4.0.0"
+    "tslint-react": "^4.0.0",
+    "webpack-theme-color-replacer": "^1.1.5"
   },
   "optionalDependencies": {
     "puppeteer": "^1.17.0"
@@ -174,4 +175,4 @@
       "create-umi"
     ]
   }
-}
+}

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

@@ -0,0 +1,26 @@
+/* eslint-disable import/no-extraneous-dependencies */
+import generate from '@ant-design/colors/lib/generate';
+import client from '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);
+    });
+    const colorPalettes = generate(color);
+    return lightens.concat(colorPalettes);
+  },
+  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, Promise);
+    this.lastColor = lastColor;
+    return promise;
+  },
+};

+ 10 - 0
src/models/setting.ts

@@ -1,6 +1,7 @@
 import { message } from 'antd';
 import { Reducer } from 'redux';
 import defaultSettings, { DefaultSettings } from '../../config/defaultSettings';
+import themeColorClient from '../components/SettingDrawer/themeColorClient';
 
 export interface SettingModelType {
   namespace: 'settings';
@@ -10,6 +11,14 @@ export interface SettingModelType {
     changeSetting: Reducer<DefaultSettings>;
   };
 }
+
+const updateTheme = (newPrimaryColor?: string) => {
+  const timeOut = 0;
+  const hideMessage = message.loading('正在切换主题!', timeOut);
+  themeColorClient.changeColor(newPrimaryColor).finally(() => hideMessage());
+};
+
+/*
 let lessNodesAppended: boolean;
 
 const updateTheme: (primaryColor?: string) => void = primaryColor => {
@@ -71,6 +80,7 @@ const updateTheme: (primaryColor?: string) => void = primaryColor => {
     buildIt();
   }
 };
+*/
 
 const updateColorWeak: (colorWeak: boolean) => void = colorWeak => {
   const root = document.getElementById('root');