vue基于webpack-theme-color-replacer 线上实时修改antd element ui主题色

2 篇文章 0 订阅
1 篇文章 0 订阅

vue 项目在线动态切换主题色;尝试了很多方法,比如:服务器端渲染判断返回对应主题css,或者动态根据主题去加载提前准备的css对应文件,还有就是服务器端渲染;这些方式都不是自己最终想要的效果!

最后是在看ant desgin vue pro 的时候学习了他们使用的切换主题的方式,个人感觉挺不错的;使用了 webpack-theme-color-replacer 插件,该插件可以从所有输出的 css 文件中提取主题颜色样式(例如 antd、element-ui 主题颜色),并制作一个仅包含颜色样式的 ‘theme-colors.css’ 文件。在您的网页运行时,客户端部分将帮助您下载此 css 文件,然后将颜色动态替换为新的自定义颜色。

1.安装 webpack-theme-color-replacer;

npm i -S webpack-theme-color-replacer

2.封装生成用于webpack 配置方法

// theme-color-replacer.plugin.config.js
// ant desgin vue 配置
// 引入webpack-theme-color-replacer
const ThemeColorReplacer = require('webpack-theme-color-replacer')
// 引入@ant-design 的 根据传入颜色 变换得到颜色值 方法
const generate = require('@ant-design/colors/lib/generate').default
// 引入默认主题配置 这里是antdv 的可以去官网查看
const ThemeObj = require('./theme')

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', // 输出css文件名 支持[contenthash] 与 [hash]
  matchColors: getAntdSerials(ThemeObj['primary-color']), // 主色系列 这里需要配置默认主题色,切换的时候是根据这里配置颜色值 去获取颜色来替换的
  // 改变样式选择器,解决样式覆盖问题
  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

3.新主题相关色生成与替换方法

// themeColor.js
import client from 'webpack-theme-color-replacer/client'
import generate from '@ant-design/colors/lib/generate'

export default {
  getAntdSerials (color) {
    // 淡化(即less的tint)
    const lightens = new Array(9).fill().map((t, i) => {
      return client.varyColor.lighten(color, i / 10)
    })
    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), // 新颜色数组,与" matchColors"一一对应
      changeUrl (cssUrl) {
        return `/${cssUrl}` // while router is not `hash` mode, it needs absolute path
      }
      // appendToEl: 'head', //optional. The element selector for appending child with `<style>`, default is 'body'. Using `appendToEl: 'body'` can make the css priority higher than any css in <head>
    }
    return client.changer.changeColor(options, Promise)
  }
}

4.用户点击颜色相关方法

import themeColor from './themeColor.js'

// color Array
const colorList = [
  {
    name: '红色',
    color: '#F55448'
  },
  {
    name: '蓝色',
    color: '#2783FE'
  }
]

// 更新主题方法
const updateTheme = newPrimaryColor => {
  //  这里可以写上切换loading 或者 提示等等 
  themeColor.changeColor(newPrimaryColor).finally(() => {
    // 切换成功后回调方法 这里可以关闭loading 或者 提示等等
  })
}

export { updateTheme, colorList }

settingTheme.vue

<template>
   <a-tooltip
     v-for="(item, index) in colorList"
     :key="index"
     class="setting-drawer-theme-color-colorBlock"
   >
     <template slot="title">
       {{ item.key }}
     </template>
     <a-tag
       :color="item.color"
       @click="changeColor(item.color)"
     >
       <a-icon
         v-if="item.color === primaryColor"
         type="check"
       />
     </a-tag>
   </a-tooltip>
 </template>
 <script>
  import { updateTheme, colorList } from './settingConfig'

  export default {
    data () {
      return {
        colorList
      }
    },
    methods: {
      changeColor (color) {
         updateTheme(color)
      }
    }
  }
</script>

5.webpack 的配置 (vue.config.js)

// 动态修改主题色配置
const createThemeColorReplacerPlugin = require('./config/theme-color-replacer.plugin.config')
module.exports = {
  // ..... other config
  plugins: [
    createThemeColorReplacerPlugin() // webpack plugins
  ]
}

这里就大功告成了

element ui 切换主题 查看

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值