动态主题定制
背景
目前接手的是一个cordova的项目,最近一个迭代的到一个需求,需要为不同的租户定制不同的主题,我们希望租户的主题能跟随租户定制。
实现思路
- 首先通过接口或者容器拿到主题标识
- 通过标识在本地匹配对应的主题数据(就是各个部分的颜色)
- 通过ajax请求本地css文件(就是我们需要更改颜色的所有样式)
- 通过我们本地获取主题色把css文件进行替换(replace 原来的锚点)
- 最后动态生成style标签写入
代码部分
因为是cordova的项目,我们提前在容器就为客户进行定制,写入了租户id.我们通过本地定制的样式进行匹配颜色
var themeConfigJSON = {
"1097660": {
standard: '#40c9c9',
dark: '#24aca8',
active: '#24aca8',
light: '#37dbdb',
selected: '#40c9c9',
activeColor: '#24aca8',
customerColor: '#24aca8',
arrangeColor: '#40c9c9',
arrangeColor1: '#efffff',
}
}
//从容器中拿id
navigator.appplugin.getAppInfo(function(id) {
_this.updateStyle(id);
});
这里就是你本地css文件,留下一些你比较好进行替换的锚点(这里@{text2},@{color1}都是自己创建的),同时需要注意的你的class权重,避免样式污染。如果你是vue项目你需要考虑取消掉模块的scoped,这里也要考虑全局样式的污染。
.theme_body{
top: @{text2}px;
background: @{color1};
}
.theme_tip{
padding-top: @{text1}px;
}
这里就是替换逻辑,把提前的锚点全部进行替换,写入我们的主题色
changeStyle: function(style){
//text1 状态栏的高度
//text2 titleBar + 状态栏高度
var color = '#fff';
var height = 0;
style = style.replace( /@{text1}/g, height);
style = style.replace( /@{color1}/g, color);
return style;
},
获取到本地匹配的颜色后,我们读取本地css文件。将替换之后的css文件写入到Head中
loadStyle(){
var _this = this;
var xmlhttp = new XMLHttpRequest();
xmlhttp.open('get', this.url, true);
xmlhttp.setRequestHeader("Content-Type", "application/json");
xmlhttp.send();
xmlhttp.onreadystatechange = function (){
if(xmlhttp.readyState == 4){
//这里就是替换之后的 css数据
var styleContent = _this.changeStyle(xmlhttp.responseText);
var style = document.createElement('style');
//这里就是本地路径的css url
style.setAttribute('path',_this.url);
style.innerHTML = styleContent.trim();
//最后写入到head中
document.head.appendChild(style);
}
};
},
总结
以上就是这个主题替换的核心思路,这个方法的好处就是,对于大量的主题有很好的拓展性。只需要增加对应的配置即可。缺点也很明显,在vue项目中需要有良好的命名习惯,尽量少用scoped,避免全局主题样式覆盖不了。同事class类名的权重也十分关键,现在less,sass成了比较常见的工具,class类名的嵌套已经成了习惯,全局覆盖变得更加痛苦。
改进方向
- 希望让全局覆盖变得不那么困难
- 初次加载的时候主题loading会有闪动