[vue] 主题设置

主题设置

开发环境

"@ant-design/icons-vue": "^6.1.0",
"ant-design-vue": "^3.2.10",
"vue": "^3.2.37",
"webpack-theme-color-replacer": "^1.4.1",
@vue/cli-service": "~5.0.8

定制主题

该功能的实现比较容易,直接在 vue.config.js 文件中,通过配置某些变量就可以非常容易的实现定制化的 UI 特性

设置属性

 css: {
        //....
        loaderOptions: { //css预设器配置项,向 CSS 相关的 loader 传递选项
            less: {//less-loader@5 直接配置选项
                lessOptions: {//定制主题-确定为特定主题 而无法切换主题
                    modifyVars: {//以下变量存在于
                      'primary-color': '#206FE6',
                    //   'error-color':'#e0002a',
                    //   'link-color': '#fafafa',
                    //   'font-size-base': '16px',
                      'height-base':'40px',
                      'height-lg':'60px',
                      'input-bg': '#F5F7FA',
                      'calendar-bg': '#F5F7FA',
                      'picker-bg': '#F5F7FA',
                      'select-background': '#F5F7FA',
                      'select-single-item-height-lg':'60px',
                      'layout-header-background':'#206FE6',
                      'menu-dark-inline-submenu-bg':'transparent',//因为菜单文字需要白色,因此对应主题色选择的是dark
                      'menu-dark-item-active-bg':'#ffffff4d',
                      'tabs-card-active-color':'#fff',
                      'table-sticky-scroll-bar-bg':'#206FE6',
                      'table-header-bg':'#F5F7FA',
                      'body-background':'rgba(216, 220, 230, 0.2)',
                      'border-radius-base':'5px',
                      'btn-height-base':'40px',
                      'btn-border-width':'0',
                      'btn-border-radius-base': '10px',
                      'card-radius': '15px',
                      'card-shadow': '7px 4px 12px 0px rgba(122, 138, 153, 0.24)',
                      'modal-header-border-color-split':'transparent',
                      'modal-footer-border-color-split':'transparent',
                      'collapse-header-bg':'transparent',
                      'collapse-content-bg':'transparent',
                    },
                    javascriptEnabled: true,
                },
            }
        }
    }

你可以找到所有可以设置的变量值在你的项目目录:
node_modules/ant-design-vue/dist/default-theme.js

根据组件可选的变量值的目录(应该是打包之前的代码,因此可读性较强):
node_modules/ant-design-vue/lib/style/themes/variable.less

需要注意,有些变量会影响整个项目,因此如果某些设置是需要全局改变的时候才需要在这里设置,否则最好是在某个 class 具体的范围内进行设置

动态主题

antd 官方提供的方式

ConfigProvider.config({
    prefixCls,
    theme: {
        primaryColor
    },
})

只能修改 ant 原有 primary-color 的颜色,并且在第一次设置有效,动态修改主题第二次开始就不在生效,除非刷新系统后重新设置

并且该方式需要提前生成对应的不同主题的设置文件,然后全部引入,根据不同的前缀用以区分使用哪个

该方式涉及文件的生成以及动态切换 less 的性能问题,以及以上没有找到有效的解决方案,因此放弃

webpack-theme-color-replacer 方式

该方式引入了 webpack-theme-color-replacer 包

需要注意:

  • 如果项目之前使用了按需引入需要去除

删除 babel.config.js 中 plugins 数组中的

    [
      // 按需加载js
      "import",
      {libraryName: "ant-design-vue", libraryDirectory: "es", style: true}
    ],

在 main.ts 中全局引入样式

import 'ant-design-vue/dist/antd.less';

theme.config.js 初始化主题的配置文件

之所以需要该文件是因为 webpack-theme-color-replacer 主要是针对的是 element-ui 框架实现的动态主题,所以需要对部分内容进行修改以适应 ant-design-vue

const ThemeColorReplacer = require('webpack-theme-color-replacer')
//该文件到自己项目的@ant-design/colors文件夹中找一下,主要是用generate方法

const generate = require('@ant-design/colors/dist/index').generate;
//根据主题色获取到对应系列的hover、select 等的颜色
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)
}

//该方法就是替换element-ui样式选择器为ant-design-vue样式选择器
const themePluginOption = {
  fileName: 'css/theme-colors-[contenthash:8].css', // 输出css文件名 支持[contenthash] 与 [hash]
  matchColors: getAntdSerials('#206fe6'), // 默认显示的主题颜色 修改后重新启动项目生效
  // 改变样式选择器,解决样式覆盖问题
  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
      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

在 vue.config.js 文件中添加


const createThemeColorReplacerPlugin = require("./theme.config");

//module.exports的configureWebpack/plugins中
configureWebpack: {
    plugins: [
        createThemeColorReplacerPlugin()
    ]
}
//设置变量modifyVars
css: {
  loaderOptions:{
    less: { //less-loader@5 直接配置选项
        lessOptions: { //定制主题-确定为特定主题 而无法切换主题
          modifyVars: {
            'primary-color': '#206FE6',
          }
        }
    }
  }
}

注意这里 primary-color 必须设置一个值表明 primary-color 会被重写,否则不生效。
‘~ant-design-vue/dist/antd.less’多次引用会导致 class 多次被重写,至少引用一次
而’~ant-design-vue/lib/style/index.less’被引用主要是为了使用变量

theme.ts 修改主题的功能文件,可以在点击切换主题时调用 setTheme 方法

import client from "webpack-theme-color-replacer/client";
// import {generate} from "@ant-design/colors";
const generate = require('@ant-design/colors/dist/index').generate;

const getAntdSerials = (color) => {
  // 淡化(即less的tint)
  const lightens = new Array(9).fill(null).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);
}
/**
 * 运行时更改主题颜色
 * @param newColor 主题色
 */
const changeColor = (newColor) => {
  console.log("changeColor")
  var options = {
    newColors:getAntdSerials(newColor), // new colors array, one-to-one corresponde with `matchColors`
    changeUrl(cssUrl) {
      console.log(cssUrl)
      return `/${cssUrl}`; // while router is not `hash` mode, it needs absolute path
    },
  };
  return client.changer.changeColor(options, Promise);
}

const setTheme = (newPrimaryColor) => {
    const hideMessage = () => console.log("正在切换主题!", 0);
    changeColor(newPrimaryColor).finally((t) => {
      setTimeout(() => {
        hideMessage();
      });
    });
};
export { setTheme };
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三知之灵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值