背景
最近做的这个项目中,有个需求就是提供一个管理员平台,可以保存配置系统的主题色,然后每次加载的时候接口读取配置。好家伙,这我之前还真没做过,同时也觉得挺有意思的,就开始去寻找各位大佬现成的方案了。上百度,掘金上搜索起来。
方案
经过我的不懈百度大概总结出来以下两种方案
替换css中主题色,写入style
由于我项目本身用了element组件,想到换肤的时候,第一时间想到去看看element换肤的实现方式。 大概分为以下几步:
- element换肤方式是保存默认主题色element-variables.scss文件,请求获取该主题色文件静态资源
- 读取该css文件并去替换css文本里面匹配换肤需要替换的颜色
- 将替换过后的css文本,写入到
style上,再挂载到document上
具体代码可以参考element
最后我也是采用了这种方法
利用css3 var
css3 var 可以定义css参数,并且通过 document.body.style.setProperty 动态改变
scss文件代码
/* var(变量名, default color) */
$app-theme-color: var(--theme-color, #C93C2A);
const theme-color = 'green' // 需要替换的主题色
document.body.style.setProperty('--theme-color', theme-color)
这种方法我没有采用,因为需求是中途来的,所以主题色没定义哈哈哈(也是懒得改了)
总结
以上两种方法我也分析了一下优劣
动态替换css中主题色,写入style
优点:
- 不考虑兼容性
缺点:
- 动态替换主题色的时候需要请求默认主题色文件,刷新浏览器的时候能够看到颜色替换过程,体验不怎么好
css3 var
优点:
- 修改之后渲染很快,刷新浏览器肉眼看不见替换颜色过程
缺点:
-
兼容性,不兼容ie,具体可以去 MND 看
-
无法在媒体查询中定义变量
-
不能继承
最终实现
好了, 分析完优缺点了,最后来说说我是怎么用第一种方式实现的吧。
当我决定用第一种方式实现的时候就必须要解决一个问题,那就是我的主题色css文件从哪儿来。由于最后的css文件都是打包出来的,所以应该从打包着手。这个时候我们就需要一个webpack插件去帮我完成这件事,本来是打算自己撸这个插件的,为了节约时间(偷懒)用了个现成的 webpack-theme-color-replacer 不过替换颜色过程是我自己写的
不过后面也看了 webpack-theme-color-replacer 原理,在 webpack 打包的时候 compiler.emit 钩子生成资源到 output 目录之前。把含有主题色css的类打包到我们传入的 fileName
vue.config.js 配置部分代码:
const ThemeColorReplacer = require('webpack-theme-color-replacer')
new ThemeColorReplacer({
matchColors: ['#C93C2A'], // colors array for extracting css file, support rgb and hsl.
fileName: 'css/theme-colors-[contenthash:8].css', //optional. css 文件.
})
替换css文本插入style 部分代码参考
// 创建style
const elStyle = document.querySelector('head').appendChild(document.createElement('style'))
elStyle.setAttribute('id', 'theme-style')
// 插入主题css替换颜色后文本
// updateStyle 正则替换匹配颜色,将默认换成需要替换的颜色val
// getCSSStringOn ajax 获取css主题文本内容
// window.__theme_COLOR_cfg.url 是项目主题文件路径
// oldVal 默认主题色
// val 替换颜色
elStyle.innerText = this.updateStyle(await this.getCSSStringOn(window.__theme_COLOR_cfg.url), [oldVal], [val])
可能参考代码不多, 但是流程说清楚就行了
关于思考
虽然做出来了,但是每次接口请求 -> 替换 -> 渲染 这个过程会肉眼可见颜色替换过程,实在是难受,而且咱也不可能阻塞渲染等让用户等着我们替换完吧。优化这个我义不容辞,等我想出来哈哈
tips: 作者憨憨新手一个,写的不好见谅见谅哈哈