背景
因为女朋友是公司的业务,想做一个主题色修改的功能,所以满足她哈哈哈哈
效果展示
实现思路
我们只需要找到页面中所有的样式内容,然后将内容里面老的主题色对应的色系全部替换为新的色系即可;
关键是我们应该如何找到页面中所有的样式内容呢?
-
获取外链的样式(link标签)内容并替换样式
-
获取页面的style标签内容并替换样式
-
获取DOM元素上的style(内联样式)
*注意:在替换外联样式的时候我们由于要通用style标签覆盖link标签引入的样式,需将link标签引入的样式中url()引入的资源./、../全部去除,否则会找不到资源
有了如上思路之后我们开始代码实现
代码实现
获取外链的样式内容并替换样式
let styleTag = document.getElementById('new-configTheme__styles')
const tagsDom = document.getElementsByTagName('link')
if (!styleTag && tagsDom.length) {
styleTag = document.createElement('style')
styleTag.setAttribute('id', 'new-configTheme__styles')
document.head.appendChild(styleTag)
const tagsDomList = Array.prototype.slice.call(tagsDom)
let innerTextCon = ''
for (let i = 0; i < tagsDomList.length; i++) {
const value = tagsDomList[i]
const tagAttributeSrc = value.getAttribute('href')
const requestUrl = getRequestUrl(tagAttributeSrc)
const styleCon = await getCSSText(requestUrl)
if (
new RegExp(oldval, 'i').test(styleCon) ||
orignalRGBRegExp.test(styleCon)
) {
innerTextCon += updateStyle(
styleCon,
orignalCluster,
newThemeCluster
)
}
}
styleTag.innerText = innerTextCon
}
获取页面的style标签
// 获取页面的style标签
const styles = [].slice
.call(document.querySelectorAll('style'))
.filter(style => {
const text = style.innerText
return new RegExp(oldval, 'i').test(text) || orignalRGBRegExp.test(text)
})
// 获取页面的style标签内容,使用updateStyle直接更新即可
styles.forEach(style => {
const { innerText } = style
if (typeof innerText !== 'string') return
style.innerText = updateStyle(
innerText,
orignalCluster,
newThemeCluster
)
})
获取DOM元素上的内链样式
// 获取DOM元素上的style
const domAll = [].slice
.call(document.getElementsByTagName('*'))
.filter((dom, index) => {
const stylCon = dom.getAttribute('style')
return (
stylCon &&
(new RegExp(oldval, 'i').test(stylCon) ||
orignalRGBRegExp.test(stylCon))
)
})
domAll.forEach(dom => {
const styleCon = dom.getAttribute('style')
dom.style = updateStyle(styleCon, orignalCluster, newThemeCluster)
})
获取对应颜色色系以及阴影颜色
// 得到需要修改的一系类颜色值
function getThemeCluster(theme) {
const clusters = [theme]
for (let i = 0; i <= 9; i++) {
clusters.push(getTintColor(theme, Number(i / 10).toFixed(2)))
}
clusters.push(getShadeColor(theme, 0.1))
return clusters
}
// 得到色调颜色
function getTintColor(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) {
return [red, green, blue].join(',')
} else {
red += Math.round((255 - red) * tint)
green += Math.round((255 - green) * tint)
blue += Math.round((255 - blue) * tint)
red = red.toString(16)
green = green.toString(16)
blue = blue.toString(16)
return `#${red}${green}${blue}`
}
}
// 获取阴影色调颜色
function getShadeColor(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 - blue) * blue)
red = red.toString(16)
green = green.toString(16)
blue = blue.toString(16)
return `#${red}${green}${blue}`
}
替换对应css内容主题颜色方法
// 样式更新
function updateStyle(stylecon, oldCulster, newCluster) {
let newStyleCon = stylecon
oldCulster.forEach((color, index) => {
let regexp = ''
if (color.split(',').length > 1) {
const rgbArr = color.split(',')
regexp = new RegExp(
'\\s*' +
rgbArr[0] +
'\\s*,\\s*' +
rgbArr[1] +
'\\s*,\\s*' +
rgbArr[2] +
'\\s*',
'ig'
)
} else {
regexp = new RegExp(color, 'ig')
}
newStyleCon = newStyleCon.replace(regexp, newCluster[index])
})
return newStyleCon
}
获取外链css文本内容
// 获取外链css文本内容
function getCSSText(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
xhr.onreadystatechange = () => {
if (xhr.readyState === 4 && xhr.status === 200) {
let styleText = xhr.responseText.replace(/@font-face{[^}]+}/, '')
styleText = formatUrlInStyle(styleText)
resolve(styleText)
}
}
xhr.open('GET', url)
xhr.send()
})
}
// 由于要通用style标签覆盖link标签引入的样式,需将link标签引入的样式中url()引入的资源./、../全部去除
function formatUrlInStyle(styleText) {
// const urlReg = /(?<=url\().*?(?=\))/g
// 此处代替上面注释的零宽断言正则表达式兼容safari浏览器
const urlReg = /url\((.*?)\)/g
let targetSrc = urlReg.exec(styleText)
while (targetSrc) {
const originSrc = targetSrc[1]
targetSrc = urlReg.exec(styleText)
if (/^(http|https):\/\//g.test(originSrc)) continue
let formatSrc = originSrc
const regexp = /^\.\.\//g
while (regexp.test(formatSrc)) {
formatSrc = formatSrc.replace(regexp, '')
}
styleText = styleText.replace(originSrc, formatSrc)
}
return styleText
}
完整代码:src/changePrimaryColor.js · liziyuan97/js-function-realization - Gitee.com