• 前端网站动态主题色解决方案


    动态主题色替换分两种: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()
      })
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    然后,我们对我们的通过方法处理我们需要转换成的主题颜色生成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
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    处理新旧主题色的函数:

    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
    },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    使用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
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    总的代码都已经一一列举,大家感兴趣可以亲自实践一下。

    🎉 有问题下方评论探讨一下。(上方代码是在 Vue2.x 版本中进行编写,大家可以根据具体的应用进行稍微改写)

    2. 系统主题色替换

    系统主题色替代方案,我只提供一下方案,代码就不具体写了。系统主题色可以通过后端请求,将用户变更的主题配色保存在sql中,每个用户修改的主题色有一个对应的表记录,下次访问的时候可以从表中取出。

    用户访问系统,系统的主题展示根据登录用户的唯一标记来从数据库查询,没有找到用默认,找到使用数据库数据。拿到则用数据库记录,没有查到等异常情况用默认主题色。

    上面就是我自己对UI 组件库主题色替换系统主题色替换的具体实现的相关介绍和具体思路,描述不清楚或者描述不对可以在下方评论。

    👏 谢谢大家花时间观看,希望大家都有所收获。

    — 微信公众号:全栈之鬼影重重 —
    在这里插入图片描述

  • 相关阅读:
    Golang Context 的使用指南
    LINUX SHELL 脚本配置阿里yum仓库
    ACM算法学习路线、清单
    CSS3 多个背景图像、线性渐变从上到下(默认)、线性渐变从左到右
    51单片机中断与定时器计数器,基于普中科技HC6800-ESV2.0
    webpack用法及构建流程
    详解JDK8中新的日期时间工具类,真的很好用
    HCIP 实验作业(ppp实验)
    jacoco和sonar
    自动控制原理3.5---线性系统的稳定性分析
  • 原文地址:https://blog.csdn.net/qq_35023116/article/details/128026084