如何作为程序员搞办公室恋情(js实现修改主题色)

背景

因为女朋友是公司的业务,想做一个主题色修改的功能,所以满足她哈哈哈哈

效果展示

实现思路

我们只需要找到页面中所有的样式内容,然后将内容里面老的主题色对应的色系全部替换为新的色系即可;

关键是我们应该如何找到页面中所有的样式内容呢

  • 获取外链的样式(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 

  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值