vue-antd 动态切换主题(一键换肤)

8,876 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天,点击查看活动详情

有时会遇到修改框架主题色的场景,比如按钮默认颜色,边框颜色,选中状态或者鼠标覆盖的颜色等等,这些都是属于同一套主题的配置。

在踩坑无数后,终于找到了一键换肤的解决方案,下面来说一说实现的历程以及最终的方案

首先可以把项目中修改的样式分为三类:

  1. 静态修改(整个系统颜色修改成固定值)
  2. 动态修改
  3. 自定义样式修改

如果项目中只需要改变为固定的主题颜色,直接静态修改即可。动态样式就是根据颜色选项切换主题色。自定义样式是我们额外增加的其它样式,不受框架影响。

静态修改

按照官方给的全局化配置 的思路,找到主题相关的配置

  1. 首先将 main.js 中引入的 antd 的css 样式文件修改为 less 文件
import 'ant-design-vue/dist/antd.less';
  1. babel.config.js 文件中,配置style为true,只有这样才能加载less文件,否则会不生效 image.png

  2. 然后在 vue.config.js 中配置 css 选项(注: 配置之后一定要重启才会生效)

css: {
    loaderOptions: {
        less: {
            lessOptions: {
                modifyVars: {
                    'primary-color': '#05AE44',
                    'link-color': '#05AE44',
                    'border-radius-base': '2px'
                },
                javascriptEnabled: true
            }
        },
    },
},

含义:

  • javascriptEnabled: true
  • modifyVars 中就是配置主题颜色变量的地方

以一个按钮为例,默认配置了一个 type='primary' 属性: <a-button type="primary">Primary Button</a-button> image.png

这时就会产生一个.ant-btn-primary样式类,这种类型的样式很难去直接覆盖,当 primary-color 配置生效后,这个样式才会被覆盖,对应的就是我们自定义的颜色了

image.png

动态修改

全局配置插件,设置less文件引入

  1. 新建一个公共的 custom.less 样式文件 ,在文件中配置需要自定义的样式类,把颜色的部分设为变量,如:
.primary {
  background:var(--theme);
  color: white;
  border-color:var(--theme);
}
  1. 在全局引入上面的less文件

image.png

  1. 在具体页面中需要换颜色的地方,配置一个变量--theme并赋值,这个变量就是我们在上面的自定义less文件中使用的变量

在页面中就可以使用class="primary"作为新的样式类生效

import { ConfigProvider } from 'ant-design-vue';
      let color = '#' // 这里的color值根据业务场景修改
      ConfigProvider.config({
            theme: {
                primaryColor: color,
            },
     });
     // const body = document.querySelector('#app');
     const body = document.querySelector('body');
     body && body.style.setProperty('--theme', color);
  1. 这种形式需要额外安装依赖
    npm i style-resources-loader
    npm i vue-cli-plugin-style-resources-loader
    
  2. vue.config.js 配置,如果不配置pluginOptions,启动vue-cli会报错 image.png
const path = require('path')
module.exports = defineConfig({
    // css相关配置
    css: {
        loaderOptions: {
            less: {
                lessOptions: {
                    import: path.resolve(__dirname, 'src/assets/css/global.less'),
                    modifyVars: {},
                    javascriptEnabled: true,
                }
            },
        },
    }
}),
pluginOptions: {
    'style-resources-loader': {
        preProcessor: 'less',
        patterns: [
            path.resolve(__dirname, 'src/assets/custom.less')
        ]
    }
}

patterns 写法有三种,都是可以的实现的(注:这里的路径不能使用 @ 符号,否则会报错)

  • patterns: ["./src/assets/custom.less", "./src/assets/custom2.less"]
  • patterns: "./src/assets/custom.less"
  • patterns: [ path.resolve(__dirname, 'src/assets/custom.less') ]

其它

另外还有一种思路是给全局的antd样式添加前缀,然后通过less指令修改文件样式,达到自定义的效果。

但到执行到lessc指令时一直执行不成功,有成功的小伙伴可以分享一下

lessLoader: {
    modifyVars: {
      '@ant-prefix': 'custom',
    },
    javascriptEnabled: true,
  }