你知道 react-color 的实现原理吗
一、前言
ReactColor 是一个优秀的 React 颜色选择器组件,官方给了多种布局供开发者选择。

笔者常用的主题为 Sketch,这种主题涵盖了颜色面板、推荐色块、RGB颜色输入等功能,比较完善。但是最近在写一个富文本编辑器,编写过程中遇到了一些问题,比如用户在点击推荐色块时,编辑器会失去焦点,无法对字体颜色进行更改。如果是编辑器自有的组件,可以使用以下代码
event.preventDefault();
该代码可以禁止浏览器默认行为,比如点击推荐色块之后只将色值向上传递,而不改变浏览器当前 focus 状态。但是 ReactColor 并没有暴露该事件,故 clone 了源码,在编辑器内集成了该组件,实现功能的同时也能够减少打包体积。
二、实现原理
本章节主要介绍 ReactColor 的实现原理,以比较有代表性的 Sketch 主题为例。

由上图可以看到,整个颜色选择器面板由这六个部分组成,分别是亮度与饱和度调节面板、色相 Hue 调节面板、透明度调节面板、当前颜色的 RGBA 与 Hex 值、推荐色块以及颜色实时预览。下面的部分就来介绍其原理实现。
2.1 HSV 色彩模型
与颜色相关的几个属性分别为亮度、饱和度、色相与透明度,与我们平时用到的 RGB 色彩模型不同,ReactColor 中用的是 HSV 色彩模型,其具体含义如下:

下面是维基百科对 HSV 色彩模型的介绍:
HSV即色相、饱和度、明度(英语:Hue, Saturation, Value),又称HSB,其中B即英语:Brightness。
至于为什么选用 HSV 色彩模型而不是直接使用 RGB,大家在使用 ReactColor 的过程中应该会发现,只要在下方的 色相 Hue 调节面板上选中了颜色,亮度与饱和度调节面板就会呈现什么颜色。举个例子:你选择了黄色,那么最上方调节面板呈现的就是黄色,差别也只是饱和度与明度不同而已。这就是使用 HSV 色彩模型的优势,让用户选择的颜色变成可预知并且方便调节的。
RGB 颜色空间利用三个颜色分量的线性组合来表示颜色,任何颜色都与这三个分量有关,而且这三个分量是高度相关的,所以连续变换颜色时并不直观,想对图像的颜色进行调整需要更改这三个分量才行。自然环境下获取的图像容易受自然光照、遮挡和阴影等情况的影响,即对亮度比较敏感。而 RGB 颜色空间的三个分量都与亮度密切相关,即只要亮度改变,三个分量都会随之相应地改变,而没有一种更直观的方式来表达,而这就是 HSV 色彩模型的优势所在。
2.2 HSV 转 RGB
上面提到,在日常的前端开发过程中还是普遍使用 RGB 色彩模型进行颜色表示,在用户设置好 HSV 值后我们需要将其转为 RGB 值,公式如下(该公式来自维基百科):
这样在用户选择完成后就可以对色彩空间实时转换,通过 onChange 回调返回给用户。
2.3 HSV 色彩模型在 ReactColor 中的实现
既然使用了 HSV 色彩模型就要考虑一下如何表示这三个变量,下面我们分两部分来讲。
2.3.1 Hue 色相
| 颜色名称 | 红绿蓝含量 | 角度 | 代表物体 |
|---|---|---|---|
| 红色 | R255,G0,B0 | 0° | 血液、草莓 |
| 橙色 | R255,G128,B0 | 30° | 火、橙子 |
| 黄色 | R255,G255,B0 | 60° | 香蕉、杧果 |
| 黄绿 | R128,G255,B0 | 90° | 柠檬 |
| 绿色 | R0,G255,B0 | 120° | 草、树叶 |
| 青绿 | R0,G255,B128 | 150° | 军装 |
| 青色 | R0,G255,B255 | 180° | 水面、天空 |
| 靛蓝 | R0,G128,B255 | 210° | 水面、天空 |
| 蓝色 | R0,G0,B255 | 240° | 海、墨水 |
| 紫色 | R128,G0,B255 | 270° | 葡萄、茄子 |
| 品红 | R255,G0,B255 | 300° | 火、桃子 |
| 紫红 | R255,G0,B128 | 330° | 墨水 |
如何横向表示色相呢,只需要一行 CSS 代码:
background: linear-gradient(to right, #f00 0%, #ff0 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100%);
这样即可大致表达出 0-360 度的色相值,效果如下:
根据鼠标拖动的位置距离左边界的距离就可以计算出色相值。
/**
* 在颜色值发生变化时实时计算相应的色相值
* @param event
*/
const handleChange = (event: any) => {
if (!ref.current) {
return;
}
const clientRect = ref.current.getBoundingClientRect();
const { width: containerWidth } = clientRect;
const x: number = typeof event.pageX === 'number' ? event.pageX : event.touches[0].pageX;
const left = x - (clientRect.left + window.pageXOffset);
let innerHue;
// 处理边界值
if (left < 0) {
innerHue = 0;
} else if (left > containerWidth) {
innerHue = 359;
} else {
const percent = (left * 100) / containerWidth;
innerHue = (360 * percent) / 100;
}
setHue(innerHue);
props.onChange({ h: innerHue });
};
2.3.2 Saturation 饱和度与 Value 明度
饱和度(S)是指色彩的纯度,越高色彩越纯,低则逐渐变灰,取0-100%的数值。明度(V)指颜色的亮度,不同的颜色具有不同的明度。
在 ReactColor 中按照如下方式来表示饱和度与明度。
其实用 CSS 表示也比较简单,使用渐变色来表示就可以实现该效果。
background: linear-gradient(to right, #fff, rgba(255, 255, 255, 0));
background: linear-gradient(to top, #000, rgba(0, 0, 0, 0));
与色相的计算方式一样,也是根据鼠标拖动的位置距离左边界和下边界的距离来计算,计算方法可以参考色相的思路。
三、总结
大家看完这篇文章应该发现代码部分其实我介绍的不多,更多还是介绍 HSV 色彩模型,以及作者为什么没有使用 RGB 表示。
如果大家去看 react-color 源码就会发现代码其实不难理解,难点还是在 HSV 的应用方法上面,大家如果有需要自己在项目里面定制化颜色选择器的话也可以根据这个思路来,一天之内就可以写出来。
四、参考资料
你知道 react-color 的实现原理吗的更多相关文章
- React Native 入门到原理(详解)
抛砖引玉(帮你更好的去理解怎么产生的 能做什么) 砖一.动态配置 由于 AppStore 审核周期的限制,如何动态的更改 app 成为了永恒的话题.无论采用何种方式,我们的流程总是可以归结为以下三部曲 ...
- 深入理解React:事件机制原理
目录 序言 DOM事件流 事件捕获阶段.处于目标阶段.事件冒泡阶段 addEventListener 方法 React 事件概述 事件注册 document 上注册 回调函数存储 事件分发 小结 参考 ...
- React Hooks 内部实现原理
React Hooks 内部实现原理 源码分析 // 链表 React Hooks 原理剖析 refs https://reactjs.org/docs/hooks-intro.html https: ...
- React Color使用
需求 - 要在react项目中实现颜色获取器功能 解决方案 - 使用react-color 依赖 - git地址:https://github.com/casesandberg/react-color ...
- React 性能调优原理
一.React影响性能的两个地方 二.调优原理
- JavaScript是如何工作的:编写自己的Web开发框架 + React及其虚拟DOM原理
这是专门探索 JavaScript 及其所构建的组件的系列文章的第 19 篇. 如果你错过了前面的章节,可以在这里找到它们: JavaScript 是如何工作的:引擎,运行时和调用堆栈的概述! Jav ...
- 关于React setState的实现原理(二)
React中的Transaction 大家学过sql server的都知道我们可以批量处理sql语句,原理其实都是基于上一篇我们说的Datch Update机制.当所有的操作均执行成功,才会执行修改操 ...
- React同构直出原理浅析
通常,当客户端请求一个包含React组件页面的时候,服务端首先响应输出这个页面,客户端和服务端有了第一次交互.然后,如果加载组件的过程需要向服务端发出Ajax请求等,客户端和服务端又进行了一次交互,这 ...
- 关于React setState的实现原理(三)
前面提到事务即将结束时,会去调用FLUSH_BATCHED_UPDATES的flushBatchedUpdates方法执行批量更新,该方法会去遍历dirtyComponents,对每一项执行perfo ...
- 关于React setState的实现原理(一)
前言 首先在学习react的时候就对setSate的实现有比较浓厚的兴趣,那么对于下边的代码,可以快速回答吗? class Root extends React.Component { constru ...
随机推荐
- Fiddle重定向请求
以当当网和淘宝网为例: 1.打开浏览器,在地址栏中输入www.dangdang.com,进入当当主页. 2.在规则编辑器中设置规则,将dangdang重定向至taobao,并打开规则. 3.再次刷新当 ...
- 用STM32定时器测量信号频率——测频法和测周法[原创cnblogs.com/helesheng]
工业测试与控制系统中,经常需要对未知信号的频率进行测试.对于10MHz以下的信号,用单片机(MCU)定时器完成这项任务显然是最常见和最佳的选择.目前性价比最高的单片机STM32拥有功能强大且数量众多的 ...
- .NET 内存泄漏的争议
前几天发布了几篇关于要小心使用 Task.Run 的文章,看了博客园的所有评论.发现有不少人在纠结示例中的现象是不是属于内存泄漏,本文分享一下我个人的看法,大家可以保留自己的意见. 在阅读本文前,如果 ...
- Jmeter(2)基础知识
一.Jmeter测试计划 1.测试计划用来描述一个性能/接口测试的脚本和场景设计 独立运行每个线程组:用于控制测试计划中的多个线程组的执行顺序.不勾选时,默认各线程组并行.随机执行. 主线程结束后运行 ...
- JavaSE10-继承&super&this&抽象类
1.继承 1.1 概述 多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那一个类即可. 其中,多个类可以称为子类,单独那一个类称为父类.超类(s ...
- Exception in thread "main" org.apache.hadoop.security.AccessControlException: Permission denied: user=Mypc, access=WRITE, inode="/":fan:supergroup:drwxr-xr-x
在window上编程提示没有写Hadoop的权限 Exception in thread "main" org.apache.hadoop.security.AccessContr ...
- Python SQLALchemy框架
SQLALchemy SQLALchemy是Python中的一款优秀的ORM框架,它可以作用于任何第三方Web框架,如flask,tornado等框架. SQLALchemy相较于DjangoORM来 ...
- strin 字符串的内置函数
count("x")统计字符串的元素的个数 a = "hello kitty" print (a.count("t"))#统计t出现的个数 ...
- 使用BulkLoad恢复hbase数据
问题: hbase 集群启动不了,maste一直在初始化,数据面临丢失风险. 解决: 把hbfs上 /hbase 目录移走 改名为/hbase-bak 删除zk上的数据,重新建立一个新的hbase集群 ...
- 【英雄帖】FreeRedis 邀请您一起优化项目。
嘿!各位!自 FreeRedis 开库以来,相继出现了很多贡献者,我们正在对 FreeRedis 的各功能模块做优化,这并不意味着现版的 FreeRedis 有问题,我们只是希望在某些方面做得更好.如 ...