ant-design-vue antd-theme-webpack-plugin 动态改变主题

2,560 阅读2分钟

首发于CSDN:ant-design-vue antd-theme-webpack-plugin 动态改变主题_kxh166的博客-CSDN博客_antd-theme-webpack-plugin 属于原创文章

安装

npm install -D antd-theme-webpack-plugin

关键源码

构造器选项:

const defaulOptions = {
  varFile: path.join(__dirname, "../../src/styles/variables.less"),
  antDir: path.join(__dirname, "../../node_modules/antd"),
  stylesDir: path.join(__dirname, "../../src/styles/antd"),
  themeVariables: ["@primary-color"],
  indexFileName: "index.html",
  generateOnce: false,
  lessUrl:
    "https://cdnjs.cloudflare.com/ajax/libs/less.js/2.7.2/less.min.js",
  publicPath: ""
};

编译过程:

compiler.hooks.emit.tapAsync('AntDesignThemePlugin', (compilation, callback) => { 
  const less = `
<link rel="stylesheet/less" type="text/css" href="${options.publicPath}/color.less" />
<script>
  window.less = {
    async: false,
    env: 'production'
  };
</script>
<script type="text/javascript" src="${options.lessUrl}"></script>
    `;
  if (
    options.indexFileName &&
    options.indexFileName in compilation.assets
  ) {
    const index = compilation.assets[options.indexFileName];
    let content = index.source();

    if (!content.match(/\/color\.less/g)) {
      index.source = () =>
        content.replace(less, "").replace(/<body>/gi, `<body>${less}`);
      content = index.source();
      index.size = () => content.length;
    }
  }

从源码可看出:若 index.html 文件中没有相关样式、脚本代码时,会自动在 body 开始标签添加

使用

环境版本:

  • @vue/cli 4.5.8
  • ant-design-vue 1.7.2
  • antd-theme-webpack-plugin 1.3.7
  • less 3.0.4
  • less-loader 5.0.0

在 vue.config.js 中

const AntDesignThemePlugin = require("antd-theme-webpack-plugin");

module.exports = {

  css: {
    loaderOptions: {
      less: {
        modifyVars: { },
        javascriptEnabled: true
      }
    },
    extract: false
  },

  configureWebpack: {
	plugins: [

	    new AntDesignThemePlugin({
		  // ant 目录
	      antDir: resolve("./node_modules/ant-design-vue"),
		  // 样式目录 会获取该目录下的 less 文件编译
	      stylesDir: resolve("./src/styles"),
		  // 变量文件 
	      varFile: resolve(
			// ant-design-vue 变量文件
	        // "./node_modules/ant-design-vue/lib/style/themes/default.less"
			// 自定义变量文件 该文件需要引入 ant-design-vue 变量文件:@import "~ant-design-vue/lib/style/themes/default.less";
	        "./src/styles/themes/variables.less"
	      ),
	      themeVariables: [
	        "@primary-color",
	        "@secondary-color",
	        "@text-color",
	        "@text-color-secondary",
	        "@heading-color",
	        "@layout-body-background",
	        "@btn-primary-bg",
	        "@layout-header-background"
	      ],
	      generateOnce: false,
		  // 默认
	      indexFileName: "index.html",
		  // 默认
	      lessUrl:
	        "https://cdnjs.cloudflare.com/ajax/libs/less.js/2.7.2/less.min.js",
		  // 实际上是项目名
	      publicPath: "/[proj_name]"
	      // customColorRegexArray: [] // An array of regex codes to match your custom color variable values so that code can identify that it's a valid color. Make sure your regex does not adds false positives.
	    })

	]
};

[proj_name] 需要修改成自身的项目名

执行 npm run build 命令生成 color.less 文件:遇到以下异常:

Building for production...error [LessError: error evaluating function `darken`: color.toHSL is not a function] {
  message: 'error evaluating function `darken`: color.toHSL is not a function',
  stack: undefined,
  type: 'Runtime',
  filename: 'input',
  index: 363260,
  line: 16057,
  column: 32,
  callLine: NaN,
  callExtract: undefined,
  extract: [
    "@table-header-sort-active-bg: ~'darken(@table-header-bg, 3%)';",
    '@table-header-filter-active-bg: darken(@table-header-sort-active-bg, 5%);',
    '@table-selection-column-width: 60px;'
  ]
}

需要在 ant-design-vue 变量文件【node_modules/ant-design-vue/lib/style/themes/default.less】加上以下使用 =========== 包裹的代码:建议在 // Table 注释下加上

// Table
// --
===========
@table-header-sort-active-bg: darken(@table-header-bg, 3%);
@table-header-filter-active-bg: darken(@table-header-sort-active-bg, 5%);
@table-selection-column-width: 60px;
===========
@table-header-bg: @background-color-light;

加上后执行 npm run build 命令成功生成 color.less 文件 查看 index.html 文件可发现 body 开始标签下多出相关的样式、脚本代码:

<body> 
<link rel="stylesheet/less" type="text/css" href="/vue-antd-admin/color.less"><script>window.less = {
    async: false,
    env: true ? 'production' : 'development',
    javascriptEnabled: true,
    modifyVars: { },
};</script><script src="https://cdnjs.cloudflare.com/ajax/libs/less.js/2.7.2/less.js"></script><noscript><strong>We're sorry but Vue Antd Admin doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript>

若要在开发环境中运行,需要将 color.less 文件复制到 public 目录,并在 public 目录中的 index.htmlbody 开始标签下添加以下代码:

<link rel="stylesheet/less" type="text/css" href="<%= BASE_URL %>color.less" />
<script>
  window.less = {
      async: false,
      env: 'production',
      javascriptEnabled: true,
      modifyVars: { },
  };
</script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/less.js/2.7.2/less.js"></script>

执行 npm run serve 命令后,在控制台测试

window.less.modifyVars({
	"@primary-color": "#db8b12", 
	'@link-color': '#ee5e7b', 
	'@btn-primary-bg': '#db8b12', 
	"@primary-color2": "#db8b12"
})

@primary-color2 在自定义变量文件定义,在其他样式文件使用时,需要先引入自定义变量文件

至此,可以成功动态修改主题,但是耗费性能。在 ant-design-vue 官方的后台管理系统 ant-design-vue-pro 使用 webpack-theme-color-replacer 动态修改,无需编译 less