• Babel 插件通关秘籍
  • Git 原理详解及实用指南
  • Nest 通关秘籍
  • React 通关秘籍
  • TypeScript 全面进阶指南
  • TypeScript 类型体操通关秘籍
  • 现代CSS
  • Babel 插件通关秘籍
  • Git 原理详解及实用指南
  • Nest 通关秘籍
  • React 通关秘籍
  • TypeScript 全面进阶指南
  • TypeScript 类型体操通关秘籍
  • 现代CSS
  • React 通关秘籍

    • 1.关于本小册
    • 2.一网打尽组件常用Hook
    • 3.Hook的闭包陷阱的成因和解决方案
    • 4.React组件如何写TypeScript类型
    • 5.React组件如何调试
    • 6.受控模式VS非受控模式
    • 7.组件实战:迷你Calendar
    • 8.组件实战:Calendar日历组件(上)
    • 9.组件实战:Calendar日历组件(下)
    • 10.快速掌握Storybook
    • 11.React组件如何写单测
    • 12.深入理解Suspense和ErrorBoundary
    • 13.组件实战:Icon图标组件
    • 14.组件实战:Space间距组件
    • 15.React.Children和它的两种替代方案
    • 16.三个简单组件的封装
    • 17.浏览器的5种Observer
    • 18.组件实战:Watermark防删除水印组件
    • 19.手写react-lazyload
    • 20.图解网页的各种距离
    • 21.自定义hook练习
    • 22.自定义hook练习(二)
    • 23.用react-spring做弹簧动画
    • 24.react-spring结合use-gesture手势库实现交互动画
    • 25.用react-transition-group和react-spring做过渡动画
    • 26.快速掌握Tailwind:最流行的原子化CSS框架
    • 27.用CSSModules避免样式冲突
    • 28.CSSInJS:快速掌握styled-components
    • 29.react-spring实现滑入滑出的转场动画
    • 30.组件实战:Message全局提示组件
    • 31.组件实战:Popover气泡卡片组件
    • 32.项目里如何快速定位组件源码
    • 33.一次超爽的React调试体验
    • 34.组件实战:ColorPicker颜色选择器(一)
    • 35.组件实战:ColorPicker颜色选择器(二)
    • 36.组件实战:onBoarding漫游式引导组件
    • 37.组件实战:Upload拖拽上传
    • 38.组件实战:Form表单组件
    • 39.React组件库都是怎么构建的
    • 40.组件库实战:构建esm和cjs产物,发布到npm
    • 41.组件库实战:构建umd产物,通过unpkg访问
    • 42.数据不可变:immutable和immer
    • 43.基于ReactRouter实现keepalive
    • 44.Historyapi和ReactRouter实现原理
    • 45.ReactContext的实现原理和在antd里的应用
    • 46.ReactContext的性能缺点和解决方案
    • 47.手写一个Zustand
    • 48.原子化状态管理库Jotai
    • 49.用react-intl实现国际化
    • 50.国际化资源包如何通过Excel和GoogleSheet分享给产品经理
    • 51.基于react-dnd实现拖拽排序
    • 52.react-dnd实战:拖拽版TodoList
    • 53.ReactPlayground项目实战:需求分析、实现原理
    • 54.ReactPlayground项目实战:布局、代码编辑器
    • 55.ReactPlayground项目实战:多文件切换
    • 56.ReactPlayground项目实战:babel编译、iframe预览
    • 57.ReactPlayground项目实战:文件增删改
    • 58.ReactPlayground项目实战:错误显示、主题切换
    • 59.ReactPlayground项目实战:链接分享、代码下载
    • 60.ReactPlayground项目实战:WebWorker性能优化
    • 61.ReactPlayground项目实战:总结
    • 62.手写MiniReact:思路分析
    • 63.手写MiniReact:代码实现
    • 64.手写MiniReact:和真实React源码的对比
    • 65.React18的并发机制是怎么实现的
    • 66.Ref的实现原理
    • 67.低代码编辑器:核心数据结构、全局store
    • 68.低代码编辑器:拖拽组件到画布、拖拽编辑json
    • 69.低代码编辑器:画布区hover展示高亮框
    • 70.低代码编辑器:画布区click展示编辑框
    • 71.低代码编辑器:组件属性、样式编辑
    • 72.低代码编辑器:预览、大纲
    • 73.低代码编辑器:事件绑定
    • 74.低代码编辑器:动作弹窗
    • 75.低代码编辑器:自定义JS
    • 76.低代码编辑器:组件联动
    • 77.低代码编辑器:拖拽优化、Table组件
    • 78.低代码编辑器:Form组件、store持久化
    • 79.低代码编辑器:项目总结
    • 80.快速掌握ReactFlow画流程图
    • 81.ReactFlow振荡器调音:项目介绍
    • 82.ReactFlow振荡器调音:流程图绘制
    • 83.ReactFlow振荡器调音:合成声音
    • 84.AudioContext实现在线钢琴
    • 85.React服务端渲染:从SSR到hydrate
    • 86.小册总结

选择颜色是常见需求,想必大家都用过 ColorPicker 组件。

比如 Chrome DevTools 的这个:

antd 也有 ColorPicker 组件:

其实浏览器原生也支持 color 类型的 input:

<input type="color" />:

功能更强大,还支持网页颜色吸取。

兼容性也很不错:

那为什么 antd 还在 5.5 版本实现一个 ColorPicker 呢?

主要是为了统一 UI,因为浏览器原生组件各个浏览器都不一样。

比如 safari 的 <input type="color"/> 是这样的:

safari 的这个做的还挺复杂的,还有一个原生的窗口来做选择,支持的功能挺多:

但这样会导致产品在各个浏览器的体验是不一致的。

出于这个原因,我们会用 antd 的 ColorPicker 组件,而不是原生的 color 类型的 input。

那这个颜色选择组件是怎么实现的呢?

这就要学习一些颜色的知识了。

颜色有很多种表示法,RGB 是最常用的,分别是 red、green、blue,还可以用十六进制标识法 #FFFFFF

R、G、B 的取值范围是 0 到 255。

颜色用空格或者逗号分隔都行,最后的 / 后面是透明度,可以用百分比或者小数:

此外,HSL 标识法也很常用,分别是色相、饱和度、亮度,/ 后面是透明度。

色相的取值范围是 0 到 360

饱和度和亮度都是 0% 到 100%

那为什么还会有 0.3turn、150deg 这种单位呢?

因为色相是色相环上的颜色:

美术生应该很熟悉这种色相环,什么相差 60 度是邻近色、相差 180 度是互补色等等。

所以色相的取值范围是 0 到 360 也就是共 360 度。

0.3 turn 就是一圈的 0.3 的地方的颜色,而 150 deg 就是 150 度的地方的颜色。

有 RGB 不就好了么?为啥还要搞个 HSL?

红绿蓝是计算机存储颜色的方式,它喜欢这种表示法,可以直接用来显示颜色。

但是对人来说,是不是还是明暗关系、色彩饱和度更容易理解一点?

所以选色的时候都是基于色相、饱和度、亮度这些东西,但存储的时候使用 RGB,最后屏幕显示颜色也是基于 RGB的。

此外,还有 HSV/HSB,这俩用明度而不是亮度,都是差不多的东西:

所以说,HSL 对人很友好,调解下明暗度、色彩饱和度等很直观。在网页里支持 RGB 和 HSL 这俩表示法。

颜色选择器一般都是基于 HSL 来做的:

你拖动下面的色彩条的时候,调节的就是色相环的位置,色相环为 0 的时候是红色、色相环 360 的时候也是红色,正好转一圈。

你拖动上面的滑块的时候,调节的就是饱和度和亮度。

图中可以看到色相没变,往下滑亮度减少、往左滑饱和度减少。

是不是很直观?调节颜色的体验很好?

那如果用 RBG 来做这种颜色调节呢?

safari 的颜色选择器里就有这个,是这样的:

是不是用起来一脸懵逼?

怎么就变成粉色了,怎么又变紫色了?

不止你懵逼,设计师用起来也懵逼。

所以颜色选择器一般都是 HSL 的,调节色相、饱和度、亮度这三者,而不是直接调节 RGB。

最后显示的时候才转成 RGB。

rgb 和 hsl 的互转算法都是固定的,可以安装用 @swiftcarrot/color-fns 这个包来做:

然后我们具体来看下 ColorPicker 的每一部分怎么实现:

下面这个透明度滑块很容易理解,拖动改变的是透明度,从 0% 到 100%,

滑块设置一个渐变背景就行。

上面色相的滑块也差不多,取值范围是 0 到 360

但它的渐变设置比较麻烦,不是两个颜色的渐变。不然从红色渐变到红色么?

而是根据取色相环不同角度的颜色来设置渐变:

比如取 0、60、120、180、240、360 这些角度共 7 个颜色来渐变:

取出的值是 0 到 360 的色相值。

最后,上面的调整饱和度亮度的部分又是怎么实现的呢?

其实也很简单,也是加了渐变,把渐变去掉就是纯色了。

一共两个渐变:

从下到上是黑色到透明的渐变。

然后从左到右是从白到透明的渐变。

这样,就可以根据 left、top 的值,计算出饱和度和亮度的值,从上到下饱和度从 100% 到 0%,从由向左饱和度从 100% 到 0%。

这样通过 3 个滑块,就实现了任意透明度、任意色相、亮度、饱和度的颜色的选取。

之后再转成计算机喜欢的 RGB 就好了。

这就是 ColorPicker 的实现原理。

有同学可能会问,那这个吸色器呢?

这个东西可不是网页里实现的,这个是原生组件,浏览器底层可以很方便的拿到网页渲染的结果,然后取色。

不过浏览器现在也有这个 api 了,叫做 EyeDropper

用起来很简单:

效果也很好:

但是你看看这个惨不忍睹的兼容性:

如果你要吸取颜色,还是用原生组件 <input type="color"/>好了。

总结

选择颜色是常见需求,可以用浏览器的 <input type="color"/> 的原生标签,也可以用 antd 的 ColorPicker 组件。

原生标签虽然支持的功能多,但是各个浏览器实现不一致。

实现这样的颜色选择组件,需要了解颜色表示法:

网页支持的颜色表示法有 RGB、HSL 两种:

RGB 是计算机喜欢的颜色表示法,可以直接用红绿蓝来显示颜色。

HSL 是人更喜欢的颜色表示法,用色相、饱和度、亮度来表示颜色,最后转成 RGB。

(HSV/HSB 和 HSL 是一样的东西,只不过叫明度而不是亮度)

ColorPicker 一般都是用 HSL 来实现的,通过滑块调节色相、饱和度、亮度,显示的时候加上几个渐变,就能实现这种组件:

理解了 HSL 颜色表示法,下节我们自己实现下 ColorPicker 组件。

上次更新: 6/21/25, 9:42 AM
贡献者: YNight
Prev
33.一次超爽的React调试体验
Next
35.组件实战:ColorPicker颜色选择器(二)