webpack-theme-color-replacer webpack插件 实现web项目 全局修改主题颜色

6 篇文章 0 订阅
2 篇文章 0 订阅

最近发现了一个非常好用的webpack插件: webpack-theme-color-replacer:

https://github.com/hzsrc/webpack-theme-color-replacer

顾名思义,可以轻松实现整个项目主题颜色的替换。

引用下插件作者的思路:

基本思路就是,webpack构建时,在emit事件(准备写入dist结果文件时)中,将即将生成的所有css文件的内容中 带有指定颜色的css规则单独提取出来,再合并为一个theme-colors.css输出文件。然后在切换主题色时,下载这个文件,并替换为需要的颜色,应用到页面上。这样,下载的样式中就只包含颜色相关的css规则,文件较小;同时它已经包含了项目中所有的css中的指定颜色样式,一次下载全部颜色样式都搞定。

首先安装插件:

npm install ---save webpack-theme-color-replacer

然后引入插件,修改配置:

https://github.com/hzsrc/ant-design-pro-vue/commit/8f7600143be405cf8de6c950070ac7a80abb1235#diff-0e893b3578ae3d5c8b98bac1c80756a7

运行时修改主题颜色:

https://github.com/hzsrc/ant-design-pro-vue/commit/8f7600143be405cf8de6c950070ac7a80abb1235#diff-807ddb6f50da674fe8e2a75236722637

具体代码示例如下:

const ThemeColorReplacer = require('webpack-theme-color-replacer')
const generate = require('@ant-design/colors/lib/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('#3BA1FE'), // 主色系列
  // 改变样式选择器,解决样式覆盖问题
  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

关键是这个文件

然后 调用插件内的方法:

changeColor (newColor) {
    var options = {
      newColors: this.getAntdSerials(newColor), // new colors array, one-to-one corresponde with `matchColors`
      changeUrl (cssUrl) {
        console.log('cssUrl', cssUrl)
        return `/${cssUrl}` // while router is not `hash` mode, it needs absolute path
      }
    }
    return client.changer.changeColor(options, Promise)
  }

通过生成的这个css/theme-colors--.css文件,找到所有指color的css规则,然后进行统一替换,其中还包括你自己另外写的color。

changeColor: function (options, promiseForIE) {
        var win = window // || global
        var Promise = promiseForIE || win.Promise
        var _this = this;
        if (!theme_COLOR_config) {
            theme_COLOR_config = win.__theme_COLOR_cfg
            var later = retry()
            if (later) return later
        }
        var oldColors = options.oldColors || theme_COLOR_config.colors || []
        var newColors = options.newColors || []
        var cssUrl = theme_COLOR_config.url || options.cssUrl;
        if (options.changeUrl) {
            cssUrl = options.changeUrl(cssUrl)
        }

        return new Promise(function (resolve, reject) {
            if (isSameArr(oldColors, newColors)) {
                resolve()
            } else {
                getCssText(cssUrl, setCssTo, resolve, reject)
            }
        })

        function retry() {
            if (!theme_COLOR_config) {
                if (_this._tryNum < 9) {
                    _this._tryNum = _this._tryNum + 1
                    return new Promise(function (resolve, reject) {
                        setTimeout(function () {
                            resolve(_this.changeColor(options, promiseForIE))
                        }, 100)
                    })
                } else {
                    theme_COLOR_config = {}
                }
            }
        }

        function getCssText(url, setCssTo, resolve, reject) {
            var elStyle = idMap[url] && document.getElementById(idMap[url]);
            if (elStyle) {
                oldColors = elStyle.color.split('|')
                setCssTo(elStyle, elStyle.innerText)
                resolve()
            } else {
                elStyle = document.querySelector(options.appendToEl || 'body')
                    .appendChild(document.createElement('style'))
                idMap[url] = 'css_' + (+new Date())
                elStyle.setAttribute('id', idMap[url])

                _this.getCSSString(url, function (cssText) {
                    setCssTo(elStyle, cssText)
                    resolve()
                }, reject)
            }
        }

        function setCssTo(elStyle, cssText) {
            cssText = _this.replaceCssText(cssText, oldColors, newColors)
            elStyle.color = newColors.join('|')
            elStyle.innerText = cssText
            theme_COLOR_config.colors = newColors
        }
    },

然后到这,我有些迷惑:其实最终css文件的路径是从全局的window下面拿到的

theme_COLOR_config = win.__theme_COLOR_cfg

但是我不太明白的是__theme_COLOR_cfg这个属性没有从window下面找到,也不知道这个属性的值是何时填进去的,麻烦知道的大佬们告知一下,谢过。

 

 

引用资料链接:

https://segmentfault.com/a/1190000016061608

https://github.com/hzsrc/webpack-theme-color-replacer


https://github.com/hzsrc/ant-design-pro-vue/commit/8f7600143be405cf8de6c950070ac7a80abb1235#diff-0e893b3578ae3d5c8b98bac1c80756a7

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 22
    评论
评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值