- 前端
- UI组件
- 小程序
- 设计系统
- 移动开发
【免费下载链接】tdesign-miniprogram
Wechat MiniProgram and Uniapp UI components lib for TDesign
ColorPicker 是 TDesign 针对 UniApp 生态提供的一体化颜色选择组件,支持 base(系统预设色)与 multiple(色板 + 系统预设色)两种形态,内置 HEX、RGB、HSL、HSV、CMYK、CSS 等十种色值格式的自由切换,并可通过usePopup快速切换为底部弹窗模式。本文以 ColorPicker 官方文档 为主线,结合@tdesign/uniapp的源码实现,从引入方式、属性/事件/插槽 API、scroll-view 场景适配到底层色值运算原理进行系统讲解,帮助开发者在表单、主题定制、绘图工具等场景中直接落地使用。
一、组件引入:easycom 与手动注册两种方式
官方推荐使用easycom 模式引入组件,配置完成后无需手动 import,即可直接在模板中使用<t-color-picker />标签。该模式是 UniApp 内置的组件自动注册机制,可减少每个页面重复 import 的样板代码。
若项目未开启 easycom,或需要在特定页面局部使用,可采用手动引入方式:
import TColorPicker from '@tdesign/uniapp/color-picker/color-picker.vue';并在页面/组件的components字段中注册后使用:
<script> import TColorPicker from '@tdesign/uniapp/color-picker/color-picker.vue'; export default { components: { TColorPicker, }, }; </script>说明:
@tdesign/uniapp是仓库中 UniApp 组件包的 npm 包名,组件源码位于 packages/uniapp-components/color-picker/,入口组件为 color-picker.vue,类型定义统一收敛在 type.ts。
二、组件类型:base 与 multiple 两种形态
基础颜色选择器(base)
默认type为base,仅展示系统预设色块区域,用户点击预设色即可完成选择:
<template> <view> <t-color-picker @change="onChange" /> </view> </template> <script> import TColorPicker from '@tdesign/uniapp/color-picker/color-picker.vue'; export default { components: { TColorPicker, }, methods: { onChange(e) { console.log('change:', e); }, }, }; </script>该示例对应仓库演示代码 packages/uniapp-components/color-picker/_example/base/index.vue。
带色板的颜色选择器(multiple)
将type指定为multiple后,组件会额外渲染 HSB 饱和度面板(saturation panel)、色相滑动条(hue slider)与可选的不透明度滑动条(alpha slider),配合系统预设色一起使用,是完整的"自由取色"形态:
<template> <view> <t-color-picker enable-alpha type="multiple" @change="onChange" @palette-bar-change="onPaletteBarChange" /> </view> </template> <script> import TColorPicker from '@tdesign/uniapp/color-picker/color-picker.vue'; export default { components: { TColorPicker, }, methods: { onChange(e) { console.log('change', e); }, onPaletteBarChange(e) { console.log('onPaletteBarChange', e); }, }, }; </script>对应演示代码见 packages/uniapp-components/color-picker/_example/multiple/index.vue。
从 template.vue 的渲染逻辑可以看到,组件内部通过isMultiple控制饱和度面板、色相/透明度滑动条、格式输入区、系统预设色区域的显隐,并且isMultiple与type属性通过 watch 实时联动(见 color-picker.vue 中的typewatcher)。
三、组件状态:色值格式(format)自由切换
format属性用于控制组件对外输出的色值格式,默认值为RGB。可选项共 10 种:
| 格式 | 示例输出 | 说明 | | -- | -- | -- | | HEX |#0052D9| 6 位十六进制色值 | | HEX8 |#0052D9FF| 8 位十六进制色值(含透明度) | | RGB |rgb(0, 82, 217)| 红绿蓝三通道 | | RGBA |rgba(0, 82, 217, 1)| 红绿蓝 + 透明度 | | HSL |hsl(217, 100%, 43%)| 色相/饱和度/明度 | | HSLA |hsla(217, 100%, 43%, 1)| HSL + 透明度 | | HSV |hsv(217, 100%, 85%)| 色相/饱和度/明度(色彩模型) | | HSVA |hsva(217, 100%, 85%, 1)| HSV + 透明度 | | CMYK |cmyk(100, 61, 0, 15)| 印刷四分色 | | CSS |rgba(...)或linear-gradient(...)| CSS 原生色值 / 渐变色 |
官方文档特别说明:当enableAlpha为真时,HEX8 / RGBA / HSLA / HSVA四种带透明通道的格式才真正有效。
format属于"组件状态"维度,通常与受控的value搭配使用。仓库示例 packages/uniapp-components/color-picker/_example/format/index.vue 展示了如何通过点击切换格式:
<template> <view> <view v-for="(list, index) in formatList" :key="index" class="format-line"> <view v-for="(item, index1) in list" :key="index1" :class="'format-item ' + (curFormat === item ? 'active' : '')" :data-format="item" @click.stop.prevent="clickFormat" > <t-icon v-if="curFormat === item" name="check" size="14" /> {{ item }} </view> </view> <t-color-picker enable-alpha type="multiple" :format="curFormat" :value="color" @change="onChange" @palette-bar-change="onPaletteBarChange" /> </view> </template> <script> import TColorPicker from '@tdesign/uniapp/color-picker/color-picker.vue'; import TIcon from '@tdesign/uniapp/icon/icon.vue'; export default { components: { TColorPicker, TIcon, }, data() { return { curFormat: 'CSS', color: '#7bd60b', formatList: [ ['CSS', 'HEX', 'RGB'], ['HSL', 'HSV', 'CMYK'], ], }; }, methods: { onChange(e) { console.log('change', e); }, onPaletteBarChange(e) { console.log('onPaletteBarChange', e); }, clickFormat(e) { this.curFormat = e.target.dataset.format; }, }, }; </script>值得说明的是:format不仅决定对外输出格式,也决定组件输入区(format-list)展示的分量数值。在 color-picker.vue 的getFormatList()中,各格式被映射到 HSV/HSL/RGB/CMYK 分量数组,并把透明度单独以百分比呈现;formatValue()则通过Color.getFormatsColorMap()[this.format]取对应格式字符串返回给change事件。
四、弹窗模式:usePopup + visible 受控显隐
默认情况下 ColorPicker 以内嵌面板形式渲染。设置use-popup(即usePopup)为true后,组件会使用底部弹出的 Popup 层包裹整个选择面板,适合在设置页、表单页等空间受限的场景中使用。此时需配合visible属性受控控制显隐:
<template> <view> <t-color-picker :visible="visible" use-popup enable-alpha type="multiple" @update:visible="(e) => (visible = e)" @change="onChange" @palette-bar-change="onPaletteBarChange" /> <t-button block size="large" variant="outline" theme="primary" @click="handlePopup"> 弹窗形式的颜色选择器 </t-button> </view> </template> <script> import TButton from '@tdesign/uniapp/button/button.vue'; import TColorPicker from '@tdesign/uniapp/color-picker/color-picker.vue'; export default { components: { TColorPicker, TButton, }, data() { return { visible: false, }; }, methods: { onChange(e) { console.log('change', e); }, handlePopup() { this.visible = true; }, onPaletteBarChange(e) { console.log('onPaletteBarChange', e); }, }, }; </script>对应演示代码见 packages/uniapp-components/color-picker/_example/use-popup/index.vue。
从 color-picker.vue 的实现细节可以补充两点:
- 弹窗模式下组件会透传
popup-props给底部 Popup,内置默认值包括show-overlay为true、z-index为11500、placement="bottom",Popup 的全部属性(closeOnOverlayClick、duration、overlayProps、usingCustomNavbar等)均可通过popup-props覆盖,完整类型定义见 packages/uniapp-components/popup/type.ts。 - 弹窗打开时会延迟约 350ms 再执行元素位置测量(
onWatchPopupVisible),这是因为 Popup 的过渡动画时长为 300ms,需等面板真正渲染完成后再计算饱和度面板与滑动条的区域尺寸,从而保证拖拽坐标换算准确。
另外,visible与dataVisible通过 watch 双向联动,点击遮罩层后组件会同步派发update:visible事件,因此示例中通过@update:visible回写visible即可形成闭环的受控状态。
五、FAQ:scroll-view 场景下的定位适配
官方文档专门提示了一个高频坑:当 ColorPicker 的使用场景位于scroll-view中时,除了需要显式指定fixed属性为true,还必须手动调用组件实例的debouncedUpdateEleRect()方法,否则面板拖拽坐标会随滚动偏移产生错位。
原文档给出的小程序侧示例(同为@tdesign/uniapp组件体系的用法):
<scroll-view type="list" scroll-y bind:scroll="onScroll"> <t-color-picker id="ColorPicker" fixed /> </scroll-view>onScroll(e) { if (!this.colorPicker) this.colorPicker = this.selectComponent('#ColorPicker'); this.colorPicker.debouncedUpdateEleRect(e); }在 UniApp 组合式/选项式 API 中,可以通过uni.createSelectorQuery()或$refs拿到组件实例后调用同名方法:
<template> <scroll-view scroll-y type="list" @scroll="onScroll"> <t-color-picker ref="ColorPicker" fixed /> </scroll-view> </template> <script> export default { methods: { onScroll(e) { this.$nextTick(() => { this.$refs.ColorPicker.debouncedUpdateEleRect(e); }); }, }, }; </script>之所以需要这一步骤,可以从源码中找到依据:color-picker.vue 在mounted中创建了防抖函数:
this.debouncedUpdateEleRect = debounce((e) => this.updateEleRect(e), 150);updateEleRect()会读取scroll-view滚动事件中的e.detail.scrollTop,并以初始面板顶部位置initTop减去当前滚动距离来更新panelRect.top。而饱和度拖拽与滑动条拖拽的坐标换算(getCoordinate())正是依赖panelRect/sliderRect的top/left值,滚动不更新这些值就会导致取色位置与实际手指位置不一致。防抖时长 150ms 与mounted中 33ms 的初始化延迟,均可在 common/utils.js 的debounce实现与组件挂载逻辑中查证。
fixed属性则对应坐标计算中的分支:当fixed(或弹窗模式usePopup)为真时,getCoordinate()使用事件中的clientY与已测量的rect.top计算 Y 坐标,而非依赖offsetTop,以此规避position:fixed容器内的定位偏差。
六、ColorPicker Props 完整 API
以下属性表完整继承自官方文档(含默认值与类型说明):
| 名称 | 类型 | 默认值 | 描述 | 必传 | | -- | -- | -- | -- | -- | | custom-style | Object | - | 自定义样式 | N | | auto-close | Boolean | true | 自动关闭。在点击遮罩层时自动关闭,不需要手动设置 visible | N | | enable-alpha | Boolean | false | 是否开启透明通道 | N | | fixed | Boolean | false | 如果 color-picker 是在一个position:fixed的区域,需要显式指定属性 fixed 为 true | N | | format | String | RGB | 格式化色值。enableAlpha为真时,HEX8/RGBA/HSLA/HSVA有效。可选项:HEX/HEX8/RGB/RGBA/HSL/HSLA/HSV/HSVA/CMYK/CSS | N | | popup-props | Object | {} | 透传 Popup 组件全部属性,TS 类型为PopupProps(见 packages/uniapp-components/popup/type.ts) | N | | swatch-colors | Array | undefined | 系统预设的颜色样例,值为null或[]则不显示系统色,值为undefined会显示组件内置的系统默认色。TS 类型:Array<string> \| null \| undefined| N | | type | String | base | 颜色选择器类型:base(仅展示系统预设内容)/ multiple(展示色板和系统预设内容)。TS 类型:TypeEnum = 'base' \| 'multiple'| N | | use-popup | Boolean | false | 是否使用弹出层包裹颜色选择器 | N | | value | String | - | 色值。支持语法糖v-model:value| N | | default-value | String | - | 色值。非受控属性 | N | | visible | Boolean | false | 是否显示颜色选择器。usePopup为 true 时有效 | N |
属性实现与校验细节
以上属性的运行时定义(含默认值与枚举校验)位于 props.ts:
format与type均内置validator,只接受文档列出的枚举值,传入非法值会被拦截;value与defaultValue的默认值均为空字符串'',组件在created阶段使用defaultValue || value || DEFAULT_COLOR初始化Color实例;swatchColors的默认值为null,而组件内置的系统预设色定义在 constants.ts 中(DEFAULT_SYSTEM_SWATCH_COLORS,为 10 个 TDesign 品牌蓝紫色系色值)。从genSwatchList()的逻辑可以看到三者取值差异:传undefined→ 使用内置默认色;传null或[]→ 隐藏系统色区域;传颜色数组 → 完全自定义预设色;- 组件默认色
DEFAULT_COLOR = '#001F97',色相最大值HUE_MAX = 360、透明度最大值ALPHA_MAX = 100等常量同样定义在 constants.ts。
受控与非受控用法
- 受控模式:使用
value(支持v-model:value语法糖),配合@change事件更新外部状态; - 非受控模式:只设置
default-value,组件内部维护色值,适合无需外部回读的简单取色场景。
七、ColorPicker Events 事件说明
| 名称 | 参数 | 描述 | | -- | -- | -- | | change |(context: { value: string, context: { color: ColorObject; trigger: ColorPickerChangeTrigger }})| 选中的色值发生变化时触发,第一个参数value表示新色值,context.color表示当前调色板控制器的色值,context.trigger表示触发颜色变化的来源。type ColorPickerChangeTrigger = 'palette-hue-bar' \| 'palette-alpha-bar' \| 'preset'| | close |(context: { trigger: ColorPickerTrigger })| 关闭按钮时触发。type ColorPickerTrigger = 'overlay'| | palette-bar-change |(context: { color: ColorObject })| 调色板控制器的值变化时触发,context.color指调色板控制器的值。interface ColorObject { alpha: number; css: string; hex: string; hex8: string; hsl: string; hsla: string; hsv: string; hsva: string; rgb: string; rgba: string; value: number; }|
事件触发来源(trigger)解析
从 color-picker.vue 的方法实现可以梳理出trigger的完整取值路径:
palette-hue-bar:拖动色相滑动条时触发(onChangeSlider({ value, isAlpha: false }));palette-alpha-bar:拖动透明度滑动条时触发(onChangeSlider({ value, isAlpha: true }));preset:点击系统预设色块时触发(clickSwatch())。
此外,饱和度面板拖拽会先派发palette-bar-change,再按实际变化的维度派发change(内部区分palette-saturation/palette-brightness/palette-saturation-brightness三种细分来源),方便需要实时预览的场景消费。
ColorObject是组件对外输出的统一色值对象,包含alpha、css、hex、hex8、hsl、hsla、hsv、hsva、rgb、rgba、value等字段,其构造逻辑见 common/shared/color-picker/color.js 中的getColorObject()。
八、ColorPicker Slots 插槽
| 名称 | 描述 | | -- | -- | | footer | 底部插槽,仅在usePopup为true时有效 | | header | 顶部插槽,仅在usePopup为true时有效 |
从 color-picker.vue 的模板结构可以看到,header/footer插槽只渲染在t-popup分支内,且分别位于面板模板(template-vue)的上方与下方,适合放置自定义标题栏、确认/取消按钮等弹窗配套元素。
九、CSS Variables 自定义样式
组件将面板、饱和度区域、滑动条、预设色块等关键样式全部抽成了 CSS 变量,开发者无需覆盖组件内部 class,直接通过变量即可实现主题定制。完整变量表如下(默认值来自官方文档):
| 名称 | 默认值 | 描述 | | -- | -- | -- | | --td-color-picker-gradient-preview-height | 56rpx | 渐变预览高度 | | --td-color-picker-gradient-preview-radius | 6rpx | 渐变预览圆角 | | --td-color-picker-gradient-preview-width | 56rpx | 渐变预览宽度 | | --td-color-picker-input-format-margin-left | 48rpx | 格式输入区左间距 | | --td-color-picker-panel-background | @bg-color-container | 面板背景色 | | --td-color-picker-panel-padding | 32rpx | 面板内边距 | | --td-color-picker-panel-radius | 24rpx | 面板圆角 | | --td-color-picker-panel-width | 750rpx | 面板宽度 | | --td-color-picker-saturation-height | 288rpx | 饱和度面板高度 | | --td-color-picker-saturation-radius | 12rpx | 饱和度面板圆角 | | --td-color-picker-saturation-thumb-size | 48rpx | 饱和度取色圆点尺寸 | | --td-color-picker-slider-height | 16rpx | 滑动条高度 | | --td-color-picker-slider-thumb-padding | 6rpx | 滑动条滑块内边距 | | --td-color-picker-slider-thumb-size | 48rpx | 滑动条滑块尺寸 | | --td-color-picker-slider-thumb-transform-x | -18rpx | 滑动条滑块水平偏移 | | --td-color-picker-slider-wrapper-padding | 0 18rpx | 滑动条容器内边距 | | --td-color-picker-swatch-border-radius | @radius-small | 预设色块圆角 | | --td-color-picker-swatch-height | 48rpx | 预设色块高度 | | --td-color-picker-swatch-padding | 0 | 预设色块内边距 | | --td-color-picker-swatch-width | 48rpx | 预设色块宽度 | | --td-color-picker-swatches-title-font | @font-title-medium | 预设色标题字体 |
这些变量在 color-picker.less 中逐一声明并被面板样式引用,且默认值均引用 TDesign 设计变量(如@bg-color-container、@radius-small、@font-title-medium),因此与整套 TDesign 主题体系天然打通。使用方式示例:
/* 自定义取色面板宽度与圆角 */ .t-color-picker { --td-color-picker-panel-width: 690rpx; --td-color-picker-panel-radius: 32rpx; --td-color-picker-saturation-height: 320rpx; }十、底层实现原理:色值运算与渐变支持
理解 ColorPicker 的"多格式输出"能力,需要看它的色值核心——Color类(packages/uniapp-components/common/shared/color-picker/color.js),它由 utils.js 统一对外导出。
1. 统一色彩模型与实时转换
Color内部以HSV 四元组(h/s/v/a)作为唯一状态源(this.states),任何输入(HEX、RGB、HSL、CMYK、渐变字符串等)都会先归一化为 HSV 状态;输出时则通过 tinycolor 库或自研转换函数即时计算各格式字符串:
rgb/rgba:hsv2rgba(this.states);hsl/hsla:hsv2hsla(this.states);hex/hex8:tinyColor(this.states).toHexString() / toHex8String();cmyk:先转 RGB,再经rgb2cmyk计算 C/M/Y/K(见 common/shared/color-picker/cmyk.js);css:普通色返回rgba(...),渐变色返回linear-gradient(...)字符串。
getFormatsColorMap()汇总了全部 10 种格式的取值函数,正是组件formatValue()与getFormatList()的数据来源。
2. 渐变色支持
Color额外维护一组gradientStates(color 点集合 + 角度 + 选中点),通过 common/shared/color-picker/gradient.js 的正则解析引擎将linear-gradient(135deg, #fff 0%, #000 100%)形式的字符串反解析为可编辑的渐变点对象,并支持在拖动色相/透明度时实时回写当前选中渐变点(updateCurrentGradientColor())。因此format="CSS"时,组件不仅能展示、还能编辑渐变色,这也解释了 CSS Variables 中--td-color-picker-gradient-preview-*一组变量的存在意义。
3. 拖拽取色的坐标换算
面板交互(饱和度拖动、色相/透明度滑动条拖动)统一走onTouchStart / onTouchMove / onTouchEnd→handleDiffDrag()→handleSaturationDrag() / handleSliderDrag()的链路:
- 饱和度:
saturation = x / width,value = 1 - y / height,结果钳制在[0, 1]; - 色相滑动条:按
x / width × HUE_MAX(360)换算并钳制; - 透明度滑动条:按
x / width × ALPHA_MAX(100)换算。
最终通过onChangeSlider()/onChangeSaturation()更新Color状态、派发palette-bar-change与change事件,再调用setCoreStyle()刷新滑块位置与格式输入区。
结语
TDesign 的 ColorPicker 组件以type(base/multiple)、format(10 种色值格式)、usePopup(内嵌/弹窗)三个核心维度覆盖了绝大多数移动端取色诉求。在 packages/uniapp-components/color-picker/ 目录下,官方还提供了 base、multiple、format、use-popup 四组可直接运行参考的演示工程(_example目录),配合本文的属性、事件、插槽与 CSS 变量说明,即可快速完成从"引入组件"到"深度定制"的完整接入。若使用中遇到scroll-view内取色偏移问题,记得按第五节方案显式设置fixed并联动调用debouncedUpdateEleRect()。
- 前端
- UI组件
- 小程序
- 设计系统
- 移动开发
【免费下载链接】tdesign-miniprogram
Wechat MiniProgram and Uniapp UI components lib for TDesign
相关推荐
element-react ColorPicker 颜色选择器完全指南:多格式颜色取值、Alpha 通道与 onChange 回调实战
element react ColorPicker 颜色选择器完全指南:多格式颜色取值、Alpha 通道与 onChange 回调实战 ColorPicker
前端UI组件设计系统Element Plus ColorPicker 颜色选择器完整指南:多格式色值、Alpha 通道与预定义色板
Element Plus ColorPicker 颜色选择器完整指南:多格式色值、Alpha 通道与预定义色板 ColorPicker 是 Element Pl
前端UI组件REA 逆向工程技能 reverse-engineer-anything 安装指南:一条命令给 AI 编码助手装好逆向工作流
REA 逆向工程技能 reverse engineer anything 安装指南:一条命令给 AI 编码助手装好逆向工作流 手上有目标程序,却没有一行源代码—
逆向工程MCP 服务AI 技能
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考