动态主题定制

背景

目前接手的是一个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类名的嵌套已经成了习惯,全局覆盖变得更加痛苦。

改进方向

  1. 希望让全局覆盖变得不那么困难
  2. 初次加载的时候主题loading会有闪动
原文地址:https://www.cnblogs.com/wangziye/p/11939728.html