前言

最近在使用vue3+ts+antd搭建后端项目,需要动态改变主题颜色,其实也是使用了pro版的方法,但是还是有坑的,我把坑排了写一下记录

开始

安装需要依赖

npm i webpack-theme-color-replacer

npm i @ant-design/colors@2.0.3

在src目录下新建config目录子文件有:

  1. theme-color-replacer.plugin.config.js
  2. themeColor.js
  3. themesettingConfig.ts

theme-color-replacer.plugin.config.js

const ThemeColorReplacer = require('webpack-theme-color-replacer');
const generate = require('@ant-design/colors/src/generate').default
const getAntdSerials = (color) => {
// 淡化(即less的tint)
const lightens = new Array(9).fill('').map((t, i) => {
return ThemeColorReplacer.varyColor.lighten(color, i / 10);
});
const colorPalettes = generate(color);
const rgb = ThemeColorReplacer.varyColor
.toNum3(color.replace('#', ''))
.join(',');
return lightens.concat(colorPalettes).concat(rgb);
};

const themePluginOption = {
fileName: 'css/theme-colors-[contenthash:8].css',
matchColors: getAntdSerials('#1890ff'), // 主色系列
// 改变样式选择器,解决样式覆盖问题
changeSelector(selector) {
switch (selector) {
case '.ant-calendar-today .ant-calendar-date':
return (
':not(.ant-calendar-selected-date):not(.ant-calendar-selected-day)' +
selector
);
case '.ant-btn:focus,.ant-btn:hover':
return '.ant-btn:focus:not(.ant-btn-primary):not(.ant-btn-danger),.ant-btn:hover:not(.ant-btn-primary):not(.ant-btn-danger)';
case '.ant-btn.active,.ant-btn:active':
return '.ant-btn.active:not(.ant-btn-primary):not(.ant-btn-danger),.ant-btn:active:not(.ant-btn-primary):not(.ant-btn-danger)';
case '.ant-steps-item-process .ant-steps-item-icon > .ant-steps-icon':
case '.ant-steps-item-process .ant-steps-item-icon>.ant-steps-icon':
return ':not(.ant-steps-item-process)' + selector;
// fixed https://github.com/vueComponent/ant-design-vue-pro/issues/876
case '.ant-steps-item-process .ant-steps-item-icon':
return ':not(.ant-steps-item-custom)' + selector;
case '.ant-menu-horizontal>.ant-menu-item-active,.ant-menu-horizontal>.ant-menu-item-open,.ant-menu-horizontal>.ant-menu-item-selected,.ant-menu-horizontal>.ant-menu-item:hover,.ant-menu-horizontal>.ant-menu-submenu-active,.ant-menu-horizontal>.ant-menu-submenu-open,.ant-menu-horizontal>.ant-menu-submenu-selected,.ant-menu-horizontal>.ant-menu-submenu:hover':
case '.ant-menu-horizontal > .ant-menu-item-active,.ant-menu-horizontal > .ant-menu-item-open,.ant-menu-horizontal > .ant-menu-item-selected,.ant-menu-horizontal > .ant-menu-item:hover,.ant-menu-horizontal > .ant-menu-submenu-active,.ant-menu-horizontal > .ant-menu-submenu-open,.ant-menu-horizontal > .ant-menu-submenu-selected,.ant-menu-horizontal > .ant-menu-submenu:hover':
return '.ant-menu-horizontal > .ant-menu-item-active,.ant-menu-horizontal > .ant-menu-item-open,.ant-menu-horizontal > .ant-menu-item-selected,.ant-menu-horizontal:not(.ant-menu-dark) > .ant-menu-item:hover,.ant-menu-horizontal > .ant-menu-submenu-active,.ant-menu-horizontal > .ant-menu-submenu-open,.ant-menu-horizontal:not(.ant-menu-dark) > .ant-menu-submenu-selected,.ant-menu-horizontal:not(.ant-menu-dark) > .ant-menu-submenu:hover';
case '.ant-menu-horizontal > .ant-menu-item-selected > a':
case '.ant-menu-horizontal>.ant-menu-item-selected>a':
return '.ant-menu-horizontal:not(ant-menu-light):not(.ant-menu-dark) > .ant-menu-item-selected > a';
case '.ant-menu-horizontal > .ant-menu-item > a:hover':
case '.ant-menu-horizontal>.ant-menu-item>a:hover':
return '.ant-menu-horizontal:not(ant-menu-light):not(.ant-menu-dark) > .ant-menu-item > a:hover';
default:
return selector;
}
},
};

const createThemeColorReplacerPlugin = () =>
new ThemeColorReplacer(themePluginOption);

module.exports = createThemeColorReplacerPlugin;

themeColor.js

import client from 'webpack-theme-color-replacer/client';
import generate from '@ant-design/colors/src/generate';

export default {
getAntdSerials(color) {
// 淡化(即less的tint)
const lightens = new Array(9).fill('').map((t, i) => {
return client.varyColor.lighten(color, i / 10);
});
// colorPalette变换得到颜色值
const colorPalettes = generate(color);
const rgb = client.varyColor.toNum3(color.replace('#', '')).join(',');
return lightens.concat(colorPalettes).concat(rgb);
},
changeColor(newColor) {
var options = {
newColors: this.getAntdSerials(newColor), // new colors array, one-to-one corresponde with `matchColors`
changeUrl(cssUrl) {
return `/${cssUrl}`; // while router is not `hash` mode, it needs absolute path
},
};
return client.changer.changeColor(options, Promise);
},
};

themesettingConfig.ts

import themeColor from './themeColor.js';
import message from 'ant-design-vue/es/message';
// import store from '../store';

const colorList = [
{
key: '薄暮',
color: '#F5222D',
},
{
key: '火山',
color: '#FA541C',
},
{
key: '日暮',
color: '#FAAD14',
},
{
key: '明青',
color: '#13C2C2',
},
{
key: '极光绿',
color: '#52C41A',
},
{
key: '拂晓蓝(默认)',
color: '#1890FF',
},
{
key: '极客蓝',
color: '#2F54EB',
},
{
key: '酱紫',
color: '#722ED1',
},
];

// 更新主题方法
const updateTheme = (newPrimaryColor: any) => {
// console.log('newPrimaryColor:', newPrimaryColor);
// store.commit('setprimaryColor', newPrimaryColor);
const hideMessage = message.loading('正在切换主题!', 0);
themeColor.changeColor(newPrimaryColor).finally(() => {
console.log('切换成功');
setTimeout(() => {
hideMessage();
}, 10);
});
};

export { updateTheme, colorList };

然后我们就搭建好了,下面开始组件使用

test.vue

<template> 
<div>
<a-divider>主题颜色</a-divider>
<div style="margin-top: .5rem">
<div style="height: 20px">
<a-tooltip class="setting-drawer-theme-color-colorBlock" v-for="(item, index) in colorList" :key="index">
<template #title>{{ item.key }}</template>
<a-tag :color="item.color" @click="changeColor(item.color)">
<check-outlined v-if="item.color == primaryColor"/>
</a-tag>
</a-tooltip>
</div>
</div>

</div>
</template>

<script lang="ts">

import { updateTheme, colorList } from '@/config/themesettingConfig';
setup () {
// 主题颜色
const primaryColor = ref('#1890FF');
function changeColor (color: string) {
if (primaryColor.value != color) {
updateTheme(color);
primaryColor.value = color;
console.log("...切换颜色...", color, primaryColor.value);
}
}
retrun {
colorList, changeColor, primaryColor
}
}

</script>

shims-vue.ts

declare module '*.js'

总结

其实也没啥好总结的,要搭配使用 webpack-theme-color-replacer 依赖 注意  @ant-design/colors 版本