首页
/ antd ColorPicker 渐变色模式实战:用 `mode` 在单色与线性渐变之间自由切换

antd ColorPicker 渐变色模式实战:用 `mode` 在单色与线性渐变之间自由切换

2026-09-06 19:03:01作者:韦蓉瑛

导读

ColorPicker 组件默认只能选取单一颜色,而通过 5.20.0 版本新增的 mode 配置,可以让同一个选择器同时支持"单色(single)"与"渐变(gradient)"两种取值形态,甚至在两者之间动态切换。本文以官方演示 line-gradient 为主线,结合仓库源码讲解 mode 的完整用法、渐变色值的数据结构、Color.toCssString() 的输出格式,以及模式切换背后状态同步的实现原理,读完后你可以直接在自己的表单与设计工具类场景中落地渐变取色能力。

mode 到底是什么:single 与 gradient 两种选择器模式

按官方 API 文档(见 index.zh-CN.md)的定义,ColorPicker 的 mode 属性用于配置选择器是"单色"还是"渐变":

参数 说明 类型 默认值 引入版本
mode 选择器模式,用于配置单色与渐变 'single' | 'gradient' | ('single' | 'gradient')[] single 5.20.0

要点如下:

  • 不传 mode:等效于 'single',面板内只出现单色取色器(饱和度/明度面与色相滑块),这是组件默认行为;
  • mode="gradient":面板直接呈现渐变编辑态,可拖拽色标、调整位置百分比;
  • mode={['single', 'gradient']}:面板顶部会出现"单色 / 渐变"两个 Tab,允许用户在使用过程中自行切换两种形态,适合需求不确定或要兼顾两种取色能力的场景。

其类型定义位于 interface.tsexport type ModeType = 'single' | 'gradient';。此外,面板切换按钮所用的文案也来自组件国际化配置,在 locale 文件中对应 singleColor(单色)与 gradientColor(渐变)两项。

逐行拆解官方 demo:line-gradient.tsx

官方演示的完整源码见 line-gradient.tsx,核心代码如下:

import React from 'react';
import { ColorPicker, Space } from 'antd';

const DEFAULT_COLOR = [
  {
    color: 'rgb(16, 142, 233)',
    percent: 0,
  },
  {
    color: 'rgb(135, 208, 104)',
    percent: 100,
  },
];

const Demo = () => (
  <Space vertical>
    <ColorPicker
      defaultValue={DEFAULT_COLOR}
      allowClear
      showText
      mode={['single', 'gradient']}
      onChangeComplete={(color) => {
        console.log(color.toCssString());
      }}
    />
    <ColorPicker
      defaultValue={DEFAULT_COLOR}
      allowClear
      showText
      mode="gradient"
      onChangeComplete={(color) => {
        console.log(color.toCssString());
      }}
    />
  </Space>
);

export default Demo;

这个 demo 里其实同时示范了四条核心能力:

  1. 默认值即是一个渐变defaultValue 传的是 { color, percent } 数组,percent: 0 表示渐变起点,percent: 100 表示渐变终点,组件据此识别出这是一个渐变颜色(与单色字符串/Color 对象区分开来);
  2. 模式选择:第一个 ColorPicker 允许用户在单色/渐变间切换,第二个则锁定为 mode="gradient"
  3. 可清除allowClear 允许清空所选颜色;
  4. 结果输出showText 在触发器上展示颜色文本,onChangeComplete 在用户完成选择时回调,其参数是包装后的 Color 实例,通过 color.toCssString() 得到可直接用于 CSS 的字符串。

onChangeComplete 与单色模式下的 onChange(value, css) 回调不同,其回调签名在 index.zh-CN.md 中定义为 (value: Color) => void,并且受控使用 value 时,拖拽过程中展示的中间颜色不会被即时回写,从而避免受控场景下拖拽卡顿。

渐变色值的内部结构:ColorType 与颜色停靠点

defaultValue 之所以能表示渐变,是因为官方在 ColorType 类型中专门定义了颜色数组这一分支,见 index.zh-CN.md

type ColorType =
  | string
  | Color
  | {
      color: string;
      percent: number;
    }[];

也就是说,ColorPicker 的取值状态分为三种形态:普通色字符串、选择器生成的 Color 对象、以及由若干"颜色 + 百分比"组成的渐变停靠点(gradient stops)数组。数组中的每一项都包含:

  • color:该停靠点的颜色值,示例中用的是 rgb(16, 142, 233) 这类 RGB 写法;
  • percent:该停靠点在渐变线上的位置百分比,取值范围通常为 0(起点)到 100(终点)。

内部实现中,这一数组会被包装为 AggregationColor(定义在 color.ts)。AggregationColor 对外暴露了几个与渐变强相关的实例方法:

  • isGradient():返回 true/false,用于判断当前颜色是否为渐变(实现见 color.ts);
  • getColors():返回内部停靠点数组,非渐变时则退化为"自身作为唯一停靠点、percent 为 0"的单元素数组(见 color.ts);
  • toCssString():将颜色序列化成 CSS 字符串。

toCssString() 的输出:linear-gradient(90deg, ...)

toCssString() 是官方在 5.20.0 加入并写进 API 文档的方法(见 index.zh-CN.md),其职责是"转换成 CSS 支持的格式"。对于渐变值,底层实现(见 color.ts)会先按百分比升序把各停靠点格式化为 rgb(...) X%,再拼接成标准线性渐变字符串:

// color.ts 中 toCssString 的核心逻辑(示意)
const colorsStr = colors.map((c) => `${c.color.toRgbString()} ${c.percent}%`).join(', ');
return `linear-gradient(90deg, ${colorsStr})`;

因此 demo 中 DEFAULT_COLOR(蓝色 → 绿色,0% → 100%)经 color.toCssString() 得到的实际输出形如:

linear-gradient(90deg, rgb(16, 142, 233) 0%, rgb(135, 208, 104) 100%)

这条字符串可以直接赋给 CSS 的 background/background-image 属性,从而让组件与业务样式无缝衔接。而非渐变的单色值走的是另一分支,直接返回 this.metaColor.toRgbString() 形式的 rgb(r, g, b) 字符串。

模式与颜色如何保持同步:useModeColor 的内部逻辑

mode 允许两种模式而用户又改了颜色形态时,组件必须保证"当前展示的模式"与"当前颜色值的形态"始终一致,这一职责由自定义 Hook useModeColor.ts 承担。从源码可以归纳出以下关键设计:

  1. 模式列表归一化:入参 mode 被统一归一化为数组,过滤空值;若为空则回退为 ['single'](对应默认值 single),随后按 singlegradient 的顺序生成面板 Tab 的可选项(见 useModeColor.ts);
  2. 模式跟随颜色自动对齐:每当颜色值变化,都会执行 setModeState(postColor.isGradient() ? 'gradient' : 'single'),即"渐变值出现 → 面板自动切到渐变模式;清成单色 → 自动切回单色模式"(见 useModeColor.ts);
  3. 受限模式下的兜底:如果外部传入的 mode 不允许当前内部 modeState(例如只允许 gradient 却被切到了 single),postMode 会回退到可选项中的第一个,从而保证渲染的模式永远落在合法集合内(见 useModeColor.ts)。

也就是说,即使你只传 mode="gradient" 而不关心颜色形态,组件内部也会用颜色自身的渐变/单色状态去对齐当前激活的 Tab,开发者无需自己维护两套状态。

单色 ↔ 渐变切换时的体验细节:颜色缓存策略

ColorPicker.tsx 中还有一个值得注意的体验优化:当用户在单色与渐变间切换模式时,源码注释明确写道:

To enhance user experience, we cache the gradient color when switch from gradient to single. If user not modify single color, we will use the cached gradient color.

对应的实现逻辑是(见 ColorPicker.tsx 附近的处理):

  • 从渐变切到单色时,会取渐变第一个停靠点的颜色作为单色值:onInternalChange(new AggregationColor(mergedColor.getColors()[0].color))
  • 但从单色切回渐变时,如果用户没有手动修改过单色,组件会优先恢复之前缓存的渐变颜色(cachedGradientColor),避免切换后渐变配置丢失;
  • 拖拽渐变过程中的中间态由 gradientDragging 状态标记,配合 onChangeComplete 保证"拖拽预览"与"完成提交"两种语义的分离。

进阶:用 presets 提供预设渐变

如果你希望把渐变作为可一键选中的预设提供给用户,可以参考同一主题下的 presets-line-gradient 演示 及其源码 presets-line-gradient.tsx。其做法是把若干组"两个颜色停靠点"组合成预设项:

const PRESET_COLORS = [
  ['rgb(42, 188, 191)', 'rgb(56, 54, 221)'],
  ['rgb(34, 73, 254)', 'rgb(199, 74, 168)'],
  ['rgb(255, 111, 4)', 'rgb(243, 48, 171)'],
  ['rgb(244, 170, 6)', 'rgb(229, 70, 49)'],
];

<ColorPicker
  mode={['single', 'gradient']}
  presets={[
    {
      label: 'Liner',
      defaultOpen: true,
      colors: PRESET_COLORS.map((colors) => [
        { color: colors[0], percent: 0 },
        { color: colors[1], percent: 100 },
      ]),
    },
  ]}
/>

presets 的类型为 PresetColorType

type PresetColorType = {
  label: React.ReactNode;
  defaultOpen?: boolean;
  key?: React.Key;
  colors: ColorType[];
};

其中每个分组的 colors 直接复用 ColorType,因此既可以放单色字符串,也可以放"颜色 + percent"数组构成的渐变。defaultOpen: true 让该预设分组在面板打开时默认展开,用户点击即可应用渐变,通常和 mode={['single', 'gradient']} 搭配使用更顺手。

测试与行为验证

仓库的 gradient.test.tsx 对渐变行为给出了可验证的断言,例如:

  • 当选择结果由渐变完成时,color.toCssString() 返回 linear-gradient(90deg, rgb(255, 0, 0) 0%) 这类标准字符串;
  • 多停靠点渐变同样会被正确序列化为完整的 linear-gradient(...) 表达式。

此外,color.tsequals() 的实现说明两个渐变颜色的相等判断是逐停靠点比较的:要求停靠点数量一致,且每个停靠点的 percent 与颜色逐一相等。这也提醒开发者:若在受控场景下想判断"渐变是否发生变化",不能只比较 toCssString() 之外的非规范化字符串,应统一使用组件生成的 Color 对象进行比对。

受控使用与 FAQ:为什么推荐用 Color 对象赋值

渐变涉及多个停靠点,若受控值来自手工拼接的颜色字符串,再做格式互转会引入精度误差。官方 FAQ(见 index.zh-CN.md)明确建议:受控场景推荐直接使用选择器生成的 Color 对象来赋值,而不是字符串色值,这样可以避免不同格式间的换算精度问题,保证取值精准、选择器按预期工作。

综合来看,mode 与渐变能力使得 antd ColorPicker 从"单一取色器"升级为"可承载设计稿色板"的取值控件:给 defaultValue 一组 { color, percent } 即可回填渐变,配合 mode 控制切换自由度,再用 onChangeCompletetoCssString() 把结果无缝注入业务样式。相关源码文件(useModeColor.tscolor.tsColorPicker.tsx)与测试(gradient.test.tsx)都可以作为进一步深入研读的起点。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
898
5.82 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
921
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.8 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
596
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
519
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
391