react,vue 如何打包后动态换肤
在开发过程种,我们碰到有时候已经打包好的项目动态换肤
通过观察发现,在body标签的第一行写入script 里面写入 setcolor 这个函数去实现,document.styleSheets 拿到所有的link引入,如果有href,通过ajax获取css内容字符串,通过replaceAll 方法,整体去替换颜色,再次引入style 从而拿到换肤的目的,由于代码还没走的标签内容,所以不会有样式由原来的样式到新样式过度的问题,而且只是进行了样式重绘
需要mathjs文件
<script> /** * primaryColor 主色,仅支持十六进制 */ function setcolor(primaryColor) { let bg1 = primaryColor; let bg2 = colorutils(primaryColor, 86) let bg3 = hexToRgb(bg1); // bg1主色,bg2处理的浅色,bg3阴影颜色 // 前面是要替换的颜色,后面对应替换成什么颜色,因每个项目不一样,改成符合自己项目的即可 let objcolor = { "#1677ff": bg1, "0 0 0 2px rgba(21,93,158,.2)": bg3, "#3276ab": bg1, "#0a4178": bg1, "#ced9de": bg2, "#78b6ed": bg2, "0 0 0 3px rgba(21,93,158,.12)": bg3, "0 0 0 5px rgba(21,93,158,.12)": bg3, "#c8d4da": bg2, "#78a8c4": bg1, "#a1c1d1": bg2 } // 将颜色变成rgba的方式 function hexToRgb(hex) { var r, g, b; if (hex.charAt(0) === "#") { hex = hex.substr(1); } r = parseInt(hex.substr(0, 2), 16); g = parseInt(hex.substr(2, 2), 16); b = parseInt(hex.substr(4, 2), 16); return "rgba(" + r + ", " + g + ", " + b + ", .2)"; } // 将颜色变成浅色color颜色opacity 0-100 越靠近0颜色越深越靠近100 颜色越浅 function colorutils(color, opacity) { function allhsl(color) { if (color.indexOf('rgb') != -1) { var start = color.indexOf('(') + 1; var startval = color.substr(color.indexOf('(') + 1) var end = startval.indexOf(')'); var val = startval.substr(0, end) var colorarr = val.split(","); return rgbtohsl(colorarr[0], colorarr[1], colorarr[2]) } else { return colorToRgb(color); } } function resultRgb(color, opacity) { var arr = allhsl(color); var result = hsltorgb(arr[0], arr[1], opacity); if (color.indexOf('rgb') != -1) { return "rgb(" + result[0] + "," + result[1] + "," + result[2] + ")"; } else { return colorToHex(result); } } function colorToRgb(color) { if (color.indexOf("#") != -1) { color = color.replace("#", "", color) } var color1 = parseInt(color.substr(0, 2), 16); var color2 = parseInt(color.substr(2, 2), 16); var color3 = parseInt(color.substr(4, 2), 16); return rgbtohsl(color1, color2, color3); } function rgbtohsl(r, g, b) { r = math.divide(r, 255); g = math.divide(g, 255); b = math.divide(b, 255); var min = Math.min(r, g, b); var max = Math.max(r, g, b); var l = math.divide(math.add(min, max), 2); var difference = math.subtract(max, min); var h, s, l; if (max == min) { h = 0; s = 0; } else { s = l > 0.5 ? math.divide(difference, math.subtract(math.subtract(2.0, max), min)) : math.divide( difference, math.add(max, min)); switch (max) { case r: h = math.add(math.divide(math.subtract(g, b), difference), (g < b ? 6 : 0)); break; case g: h = math.add(2.0, math.divide(math.subtract(b, r), difference)); break; case b: h = math.add(4.0, math.divide(math.subtract(r, g), difference)); break; } h = Math.round(math.multiply(h, 60)); } s = Math.round(math.multiply(s, 100)); l = Math.round(math.multiply(l, 100)); return [h, s, l]; } function hsltorgb(h, s, l) { var h = math.divide(h, 360); var s = math.divide(s, 100); var l = math.divide(l, 100); var rgb = []; if (s == 0) { rgb = [Math.round(math.multiply(l, 255)), Math.round(math.multiply(l, 255)), Math.round(math .multiply(l, 255))]; } else { var q = l >= 0.5 ? math.subtract(math.add(l, s), math.multiply(l, s)) : math.multiply(l, math.add(1, s)); var p = math.subtract(math.multiply(2, l), q); var tr = rgb[0] = math.add(h, math.divide(1, 3)); var tg = rgb[1] = h; var tb = rgb[2] = math.subtract(h, math.divide(1, 3)); for (var i = 0; i < rgb.length; i++) { var tc = rgb[i]; if (tc < 0) { tc = math.add(tc, 1); } else if (tc > 1) { tc = math.subtract(tc, 1); } switch (true) { case (tc < math.divide(1, 6)): tc = math.add(p, math.multiply(math.multiply(math.subtract(q, p), 6), tc)); break; case (math.divide(1, 6) <= tc && tc < 0.5): tc = q; break; case (0.5 <= tc && tc < math.divide(2, 3)): tc = math.add(p, math.multiply(math.subtract(q, p), math.subtract(4, math.multiply(6, tc)))); break; default: tc = p; break; } rgb[i] = Math.round(math.multiply(tc, 255)); } } return rgb; } function colorToHex(color) { function componentToHex(c) { var hex = c.toString(16); return hex.length == 1 ? "0" + hex : hex; } return "#" + componentToHex(color[0]) + componentToHex(color[1]) + componentToHex(color[2]); } return resultRgb(color, opacity) } // 获取到所有的样式 通过ajax拿到内容做替换,然后在生成style内容放到head标签下 let styleSheets = document.styleSheets; for (let i = 0; i < styleSheets.length; i++) { let obj = styleSheets[i]; if (obj && obj.href) { let links = document.querySelectorAll("link"); for (let r = 0; r < links.length; r++) { let linknode = links[r]; if (linknode.href == obj.href) { linknode.remove() } } const xhr = new XMLHttpRequest(); xhr.open('GET', obj.href, false); xhr.send(null); if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) { let str = xhr.response for (let k in objcolor) { str = str.replaceAll(k, objcolor[k]) } let nod = document.createElement('style') nod.type = 'text/css'; if (nod.styleSheet) { //ie下 nod.styleSheet.cssText = str; } else { nod.innerHTML = str; //或者写成 nod.appendChild(document.createTextNode(str)) } document.getElementsByTagName('head')[0].appendChild(nod); } } } } setcolor("#1677ff") </script>
vue将上面代码放在body下的第一行,react同理 通过这个方法就可以在打包好的文件里面就可以动态换肤了
打包后的效果