当前位置: 首页 > news >正文

前端如何实现更换项目主题色的功能?

1、场景

有一个换主题色的功能,如下图:
在这里插入图片描述

切换颜色后,将对页面所有部分的色值进行重新设置,符合最新的主题色。

2、实现思路

因为色值比较灵活,可以任意选取,所以最好的实现方式是,根据设置的色值,拼接相应的 style 标签代码,对样式进行覆盖。

3、实现步骤

3.1、获取深浅色

当前公司的组件库设计的时候,对于同一组件的颜色设置基本有三种:正常色、较深色(常用于hover效果)、较浅色(常用于边框),所以第一步是可以根据正常色,获取深浅色。

3.1.1、获取 HSL 色值

深浅色的获取,基本是通过设置 HSL 颜色的亮度实现,所以第一步是将任意格式的色值,转换为 HSL 格式。

3.1.1.1、将 RGB 颜色转为 HSL

因可能会存入 RGB 颜色,所以需要将 RGB 转为 HSL 。下面是代码:

// rgb to hsl
function rgbToHsl (color) {let aColor = color.replace(/(?:\(|\)|rgb|RGB)*/g, '').split(',')const _R = aColor[0] / 255const _G = aColor[1] / 255const _B = aColor[2] / 255const Cmax = Math.max(_R, _G, _B)const Cmin = Math.min(_R, _G, _B)const V = Cmax - Cminlet H = 0if (V === 0) {H = 0} else if (Cmax === _R) {H = 60 * (((_G - _B) / V) % 6)} else if (Cmax === _G) {H = 60 * ((_B - _R) / V + 2)} else if (Cmax === _B) {H = 60 * ((_R - _G) / V + 4)}H = Math.floor(backCycle(H, 360))const L = numberFixed((Cmax + Cmin) / 2)const S = V === 0 ? 0 : numberFixed(V / (1 - Math.abs(2 * L - 1)))return `hsl(${H},${numberFixed(100 * S)}%,${numberFixed(100 * L)}%)`
}function numberFixed (num = 0, count = 3) {const power = Math.pow(10, count)return Math.floor(num * power) / power
}function backCycle (num, cycle) {let index = num % cycleif (index < 0) {index += cycle}return index
}
3.1.1.2、将 HEX 颜色转为 HSL

因可能会存入 HEX 颜色,所以需要将 HEX 转为 HSL 。具体步骤是,先将 HEX 转为 RGB,再将 RGB 转为 HSL

// hex 转 rgb
function hexToRgb (color) {if (color.length === 4) {let sColorNew = '#'for (let i = 1; i < 4; i += 1) {sColorNew += color.slice(i, i + 1).concat(color.slice(i, i + 1))}color = sColorNew}// 处理六位的颜色值let sColorChange = []for (let i = 1; i < 7; i += 2) {sColorChange.push(parseInt('0x' + color.slice(i, i + 2)))}return 'RGB(' + sColorChange.join(',') + ')'
}RGB 转 HSL 见上部分。
3.1.2、HSL色值调亮度

HSL 调亮度,主要是改最后一位数字的值,代码如下:

// 获取更浅或者更暗的颜色,color为主色;amt为正数时获得浅色,为负数时获得深色。
function lightenDarkenColor (color, amt) {let hColor = colorToHsl(color).replace(/(?:\(|\)|hsl|HSL)*/g, '').split(',')let H = hColor[0]let S = getPercentNumber(hColor[1])let L = getPercentNumber(hColor[2]) + amt / 100L = L > 1 ? 0.98 : Lreturn `hsl(${H},${numberFixed(100 * S)}%,${numberFixed(100 * L)}%)`
}// 获取百分数的数值
function getPercentNumber (numberStr) {numberStr += ''if (numberStr.indexOf('%') > -1) {return parseFloat(numberStr) / 100} else {return parseFloat(numberStr)}
}

3.2、生成 style 代码

根据上面生成的深浅色,拼接 style 代码,对组件库和项目的色值进行覆盖,需要注意组件库的代码和项目中的代码要分开。
代码生成示例如下:

// 顶部导航的换肤 class
export let headerSkin = ({ skinColor, skinColorDarken, skinColorLighten } = {}) => {return `#skin .a-n-menu-primary ,#skin .a-n-menu-submenu .a-n-menu-submenu .a-n-menu .a-n-menu-item-active:not(.a-n-menu-submenu):before{background: ${skinColor};}#skin .a-n-menu-horizontal .a-n-menu-submenu:hover,#skin .a-n-menu-horizontal .a-n-menu-submenu:active,#skin .a-n-menu-horizontal .a-n-menu-item:hover,#skin .a-n-menu-horizontal .a-n-menu-item-active {background: ${skinColorDarken};}#skin .a-n-menu-vertical .a-n-menu-submenu .a-n-menu-item-selected>span.slotItem{color: ${skinColor};}#skin .a-n-menu-submenu {.a-select-dropdown {.a-n-menu-item:hover{background: ${skinColorLighten}}}}#skin .aw-header .icon-container-right:hover,#skin .aw-header .icon-container:hover {background: ${skinColorDarken};}`
}

3.3、将 style 放到 head 中,完成主题色的替换

let css = 上面生成的style代码。
var head = document.getElementsByTagName('head')[0]
skinStyle = document.createElement('style')
skinStyle.innerHTML = css
head.appendChild(skinStyle)

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 全面整理人工智能(AI)学习路线图及资源推荐
  • 深度学习项目 -7-使用 Python 的手写数字识别
  • 多种方式防止表单重复提交
  • Docker容器资源限制
  • day2 PS教程——搞定图层的使用方法,效率大翻倍
  • 论文速递 | Operations Research 6月文章合集
  • 华为od机试真题:求字符串所有整数最小和(Python)
  • 螺旋矩阵(模拟)
  • Python爬虫知识体系-----Selenium
  • 服务器给根目录扩展磁盘(不使用lvm逻辑券)两种方式
  • 图形编辑器基于Paper.js教程12:井身结构编辑器,多条完全平行的弯曲线,使用额外平行线来作为弯曲中心线的度量尺
  • AI绘画Stable Diffusion XL 强烈推荐!摄影后期首选,极致人像!一键磨皮,高清画质 ,商用级AI人像——TIME时光4
  • Python 提取excel中嵌入的图片
  • WPF的5种绑定模式
  • 必应Bing国内广告开户、投放流程和避坑攻略!
  • CSS 三角实现
  • CSS相对定位
  • js递归,无限分级树形折叠菜单
  • react-native 安卓真机环境搭建
  • STAR法则
  • UEditor初始化失败(实例已存在,但视图未渲染出来,单页化)
  • vue和cordova项目整合打包,并实现vue调用android的相机的demo
  • 缓存与缓冲
  • 紧急通知:《观止-微软》请在经管柜购买!
  • 融云开发漫谈:你是否了解Go语言并发编程的第一要义?
  • 想使用 MongoDB ,你应该了解这8个方面!
  • 做一名精致的JavaScripter 01:JavaScript简介
  • kubernetes资源对象--ingress
  • Play Store发现SimBad恶意软件,1.5亿Android用户成受害者 ...
  • 长三角G60科创走廊智能驾驶产业联盟揭牌成立,近80家企业助力智能驾驶行业发展 ...
  • ​ ​Redis(五)主从复制:主从模式介绍、配置、拓扑(一主一从结构、一主多从结构、树形主从结构)、原理(复制过程、​​​​​​​数据同步psync)、总结
  • (1)虚拟机的安装与使用,linux系统安装
  • (3) cmake编译多个cpp文件
  • (5)STL算法之复制
  • (Demo分享)利用原生JavaScript-随机数-实现做一个烟花案例
  • (蓝桥杯每日一题)love
  • (转) Android中ViewStub组件使用
  • (转载)(官方)UE4--图像编程----着色器开发
  • .Net 访问电子邮箱-LumiSoft.Net,好用
  • .NET 将混合了多个不同平台(Windows Mac Linux)的文件 目录的路径格式化成同一个平台下的路径
  • .NET/C# 编译期间能确定的相同字符串,在运行期间是相同的实例
  • .NET:自动将请求参数绑定到ASPX、ASHX和MVC(菜鸟必看)
  • .NET6 开发一个检查某些状态持续多长时间的类
  • .NET8.0 AOT 经验分享 FreeSql/FreeRedis/FreeScheduler 均已通过测试
  • .Net转Java自学之路—SpringMVC框架篇六(异常处理)
  • .secret勒索病毒数据恢复|金蝶、用友、管家婆、OA、速达、ERP等软件数据库恢复
  • /proc/stat文件详解(翻译)
  • @cacheable 是否缓存成功_让我们来学习学习SpringCache分布式缓存,为什么用?
  • @ConditionalOnProperty注解使用说明
  • [ IDE ] SEGGER Embedded Studio for RISC-V
  • [2015][note]基于薄向列液晶层的可调谐THz fishnet超材料快速开关——
  • [Angular] 笔记 20:NgContent
  • [Bada开发]初步入口函数介绍
  • [c++] C++多态(虚函数和虚继承)
  • [caffe(二)]Python加载训练caffe模型并进行测试1