动态主题色替换分两种:UI 组件库主题色替换
和系统主题色替换
。
组件库 UI 动态主题替换现阶段只在 Element-UI 和 Vant-UI 测试过,根据排查这种方案应该适用于所有类似的动态主题色替换场景。
1. UI 组件库主题色替换
在进入到这一部分之前,需要了解PC和移动端项目在本地或者在正式运行环境运行的情况下,项目文件是不可以写的。
首先,通过 XHR 请求获取到远程原始的 css 资源。拿到原始数据之后,我们存在在某个变量中,便于后期处理。
/**
* 获取远程 css 内容,便于二次修改 css 样式
* @param {url} string css 存放地址(记得解决跨域问题)
* @param {variable} string 读取 css 内容之后,赋予的值的变量名
*/
getCSSString (url, variable) {
return new Promise(resolve => {
const xhr = new XMLHttpRequest()
xhr.onreadystatechange = () => {
if (xhr.readyState === 4 && xhr.status === 200) {
this[variable] = xhr.responseText.replace(/@font-face{[^}]+}/, '')
resolve()
}
}
xhr.open('GET', url)
xhr.send()
})
}
然后,我们对我们的通过方法处理我们需要转换成的主题颜色生成themeCluster
。同时,我们以相同的方式处理原始的主题颜色生成originalCluster
。最后,我们需要通过正则的方式,用新的主题色取代原始的主题色,输出处理后的数据,得到处理完的数据后,将数据动态的写入到header
头部。
由此一个替换组件主题色的流程结束。涉及的代码如下:
/**
* 动态往头部插入 style 标签
* @param {variable} string 存在的变量
* @param {id} string 用于标记 style attr
* @param {color} 要替换的主题颜色
*/
getHandler (variable, id, color) {
return () => {
const themeCluster = this.getThemeCluster(color.replace('#', ''))
const originalCluster = this.getThemeCluster(ORIGINAL_THEME.replace('#', ''))
const newStyle = this.updateStyle(this[variable], originalCluster, themeCluster)
let styleTag = document.getElementById(id)
if (!styleTag) {
styleTag = document.createElement('style')
styleTag.setAttribute('id', id)
document.head.appendChild(styleTag)
}
styleTag.innerText = newStyle
}
}
处理新旧主题色的函数:
getThemeCluster(theme) {
const tintColor = (color, tint) => {
let red = parseInt(color.slice(0, 2), 16)
let green = parseInt(color.slice(2, 4), 16)
let blue = parseInt(color.slice(4, 6), 16)
if (tint === 0) { // when primary color is in its rgb space
return [red, green, blue].join(',')
} else {
red += Math.round(tint * (255 - red))
green += Math.round(tint * (255 - green))
blue += Math.round(tint * (255 - blue))
red = red.toString(16)
green = green.toString(16)
blue = blue.toString(16)
return `#${red}${green}${blue}`
}
}
const shadeColor = (color, shade) => {
let red = parseInt(color.slice(0, 2), 16)
let green = parseInt(color.slice(2, 4), 16)
let blue = parseInt(color.slice(4, 6), 16)
red = Math.round((1 - shade) * red)
green = Math.round((1 - shade) * green)
blue = Math.round((1 - shade) * blue)
red = red.toString(16)
green = green.toString(16)
blue = blue.toString(16)
return `#${red}${green}${blue}`
}
const clusters = [theme]
for (let i = 0; i <= 9; i++) {
clusters.push(tintColor(theme, Number((i / 10).toFixed(2))))
}
clusters.push(shadeColor(theme, 0.1))
return clusters
},
使用replace
方式通过匹配正则去将原始主题色换成新的主题色。
/**
* 用新的 color 替换旧的 color
* @param {*} style
* @param {*} oldCluster 旧 color
* @param {*} newCluster 新 color
*/
updateStyle(style, oldCluster, newCluster) {
let newStyle = style
oldCluster.forEach((color, index) => {
newStyle = newStyle.replace(new RegExp(color, 'ig'), newCluster[index])
})
return newStyle
}
总的代码都已经一一列举,大家感兴趣可以亲自实践一下。
🎉 有问题下方评论探讨一下。(上方代码是在 Vue2.x 版本中进行编写,大家可以根据具体的应用进行稍微改写)
2. 系统主题色替换
系统主题色替代方案,我只提供一下方案,代码就不具体写了。系统主题色可以通过后端请求,将用户变更的主题配色保存在sql
中,每个用户修改的主题色有一个对应的表记录,下次访问的时候可以从表中取出。
用户访问系统,系统的主题展示根据登录用户的唯一标记来从数据库查询,没有找到用默认,找到使用数据库数据。拿到则用数据库记录,没有查到等异常情况用默认主题色。
上面就是我自己对UI 组件库主题色替换
和系统主题色替换
的具体实现的相关介绍和具体思路,描述不清楚或者描述不对可以在下方评论。
👏 谢谢大家花时间观看,希望大家都有所收获。
— 微信公众号:全栈之鬼影重重 —