实现antd一键更换皮肤

2,728 阅读1分钟

react antd-theme-generator 换肤

antd 换肤

创建antd-demo项目

# 创建项目
$ npx create-react-app antd-demo

# 启动项目
$ cd antd-demo
$ yarn install
$ npm start

# 安装antd-theme-generator
$ yarn add antd-theme-generator --dev

# antd
$ yarn add antd

# 创建文件
$ touch color.js
$ mkdir src/styles
$ touch src/styles/main.less src/styles/vars.less

color.js

const path = require('path');
const fs = require('fs');
// const {generateTheme, getLessVars} = require('../../index');
// const { generateTheme, getLessVars } = require('../../../antd-theme-webpack-plugin/');
const {generateTheme, getLessVars} = require('antd-theme-generator');

const themeVariables = getLessVars(path.join(__dirname, './src/styles/vars.less'));
const defaultVars = getLessVars('./node_modules/antd/lib/style/themes/default.less');
const darkVars = {
    ...getLessVars('./node_modules/antd/lib/style/themes/dark.less'),
    '@primary-color': defaultVars['@primary-color'],
    '@picker-basic-cell-active-with-range-color': 'darken(@primary-color, 20%)'
};
const lightVars = {
    ...getLessVars('./node_modules/antd/lib/style/themes/compact.less'),
    '@primary-color': defaultVars['@primary-color']
};
// fs.writeFileSync('./src/dark.json', JSON.stringify(darkVars));
// fs.writeFileSync('./src/light.json', JSON.stringify(lightVars));
// fs.writeFileSync('./src/theme.json', JSON.stringify(themeVariables));

const options = {
    stylesDir: path.join(__dirname, './src'),
    antDir: path.join(__dirname, './node_modules/antd'),
    varFile: path.join(__dirname, './src/styles/vars.less'),
    themeVariables: Array.from(
        new Set([...Object.keys(darkVars), ...Object.keys(lightVars), ...Object.keys(themeVariables)])
    ),
    outputFilePath: path.join(__dirname, './public/color.less')
};

generateTheme(options)
    .then(less => {
        console.log('Theme generated successfully');
    })
    .catch(error => {
        console.log('Error', error);
    });

生成 public/color.less

$ node color.js

public/index.html

<body>
    <link rel="stylesheet/less" type="text/css" href="%PUBLIC_URL%/color.less" />
    <script>
        window.less = {
            async: true,
            env: 'production'
        };
    </script>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/less.js/2.7.2/less.min.js"></script>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
</body>

浏览器 console

window.less
{version: Array(3), data: {…}, tree: {…}, Environment: ƒ, AbstractFileManager: ƒ, …}

package.json

"scripts": {
    "start": "npm run color && react-scripts start",
    "build": "npm run color && react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "color": "node color.js"
}

控制台报错 console

Warning: findDOMNode is deprecated in StrictMode. findDOMNode was passed an instance of Wave which is inside StrictMode. Instead, add a ref directly to the element you want to reference. Learn more about using refs safely

src/index.js

ReactDOM.render(<App />, document.getElementById('root'));
// ReactDOM.render(
//     <React.StrictMode>
//         <App />
//     </React.StrictMode>,
//     document.getElementById('root')
// );

安装 customize-cra

$ touch config-overrides.js

$ yarn add customize-cra  react-app-rewired --dev

config-overrides.js

/**
 * @file config
 */
const {override, fixBabelImports, addLessLoader} = require('customize-cra');
// https://github.com/arackaf/customize-cra/blob/HEAD/api.md
module.exports = override(
    fixBabelImports('import', {
        libraryName: 'antd',
        libraryDirectory: 'es',
        style: true
    }),
    addLessLoader({
        lessOptions: {
            javascriptEnabled: true
        }
    })
);
$ yarn add --dev less less-loader

package.json

"scripts": {
    "start": "npm run color && react-app-rewired start",
    "build": "npm run color && react-app-rewired build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "color": "node color.js"
},

运行npm start报错

Failed to compile
./src/index.js
Error: Cannot find module 'babel-plugin-import' from '/Users/v_lishaohai/Desktop/study/react/antd-demo'
   at Array.map (<anonymous>)
$ yarn add babel-plugin-import --dev

$ yarn add postcss --dev

设置默认的主题色

src/styles/vars.less

@import '~antd/lib/style/themes/default.less';

@primary-color: #f00; // 全局主色

浏览器控制台 console

window.less.modifyVars({'@primary-color': '#00f'});

即可以看到效果


src/App.js

/**
 * @file App.js
 */
import {useState, useEffect} from 'react';
import './App.css';
import {Button} from 'antd';

const THEME_RED = '#f00';
const THEME_BLUE = '#1890ff';

export default function App() {
    const [theme, setTheme] = useState(THEME_BLUE);

    useEffect(() => {
        window.less.modifyVars({
            '@primary-color': theme
        });
        // effect
        return () => {};
    }, [theme]);

    return (
        <div className="App">
            <Button type="primary">当前主题颜色:{theme}</Button>
            <hr />
            <Button onClick={() => setTheme(THEME_RED)} type="default">
                主题红色: {THEME_RED}
            </Button>

            <Button onClick={() => setTheme(THEME_BLUE)} type="default">
                主题蓝色:{THEME_BLUE}
            </Button>
        </div>
    );
}

最终效果

源码地址

项目源码地址:https://github.com/xieerduos/antd-theme-demo