dp-color-picker
v1.0.4
Published
A color picker component with gradient support for Vue 3
Downloads
211
Maintainers
Readme
dp-color-picker 是一款基于 Vue 3 + TypeScript 开发的高级颜色选择器组件。它不仅支持标准的单色(Solid)选择,还内置了强大的渐变色(Gradient)编辑功能。组件集成了透明度调节、HSV/RGB/HEX 格式切换、系统预设颜色面板以及智能的“最近使用颜色”记录功能。其设计目标是为开发者提供一个开箱即用、交互流畅且高度可配置的色彩解决方案,适用于各类设计工具、后台管理系统及个性化配置场景。
技术依赖:
- Vue:
^3.5.24
效果预览
| 单色模式 | 渐变模式 | | :---: | :---: | | | |
2. 能力说明
| 功能模块 | 功能点 | 说明 | |:--------|:-------|:-----| | 色彩模式 | 单色/渐变切换 | 支持纯色、线性渐变(Linear Gradient)及径向渐变(Radial Gradient)的无缝切换与编辑。 | | 色彩空间 | 多格式支持 | 支持 HEX、RGB(A)、CSS 格式输入输出;内部使用 HSV 模型保证色彩计算精度。 | | 透明度 | Alpha 通道 | 提供独立的透明度滑块,支持 0-100% 透明度调节。 | | 交互体验 | 拖拽操作 | 饱和度面板、色相带、透明度带及渐变轴均支持流畅的拖拽交互,采用 RAF 优化性能。 | | 预设管理 | 系统预设 | 内置 20 种常用标准色,支持通过 Props 自定义。 | | 历史记录 | 最近使用颜色 | 自动记录用户最近选择的颜色,支持去重、持久化存储(LocalStorage)、最大数量限制及一键清除。 | | 渐变编辑 | 多色标支持 | 支持添加(双击)、删除(右击)、拖拽渐变色标(Stop),可调节渐变角度(仅线性)或切换渐变类型。 |
性能特征:
- 高性能渲染: 拖拽交互均使用
requestAnimationFrame进行节流处理,避免高频 DOM 操作导致的卡顿。 - 按需更新: 仅在必要时更新 DOM 和触发计算属性。
限制条件:
- 即使关闭
enableAlpha,内部计算仍保留 Alpha 通道,输出时会根据格式自动截断。 - 径向渐变(Radial Gradient)目前默认使用
circle at center形状和位置,暂不支持复杂的形状/位置自定义配置(但可正确解析和显示)。
3. Props 规范
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|:-------|:-----|:-----|:-------|:-----|
| modelValue | string | 是 | '#000000' | 绑定的颜色值,支持 v-model。可以是 HEX、RGBA 或 CSS 渐变字符串。 |
| defaultColor | string | 否 | '#000000' | 当 modelValue 为空时的回退颜色。 |
| enableAlpha | boolean | 否 | true | 是否启用透明度(Alpha)滑块及输出支持。 |
| format | 'HEX' \| 'RGB' | 否 | 'HEX' | 颜色输出格式。⚠️ 注意:渐变模式下始终输出 CSS 渐变字符串。 |
| swatchColors | string[] | 否 | [...] | 系统预设颜色列表。默认包含 20 种常用色。 |
| recentColors | string[] | 否 | [] | 初始最近使用颜色列表。 |
| enableRecentColors| boolean | 否 | true | 是否启用“最近使用颜色”功能。 |
| maxCount | number | 否 | 10 | 最近使用颜色的最大记录数量(1-20)。 |
| clearable | boolean | 否 | false | 是否显示清除按钮,点击可将颜色值重置为空字符串。 |
| zIndex | number | 否 | 2000 | 弹出面板的 z-index 层级。 |
| placement | string | 否 | 'bottom-start' | 弹出面板位置。可选:bottom-start, bottom-end, top-start, top-end。 |
| threshold | number | 否 | 20 | 边缘检测阈值(像素),用于自动调整弹出位置。 |
| animationDuration | number | 否 | 200 | 面板显示/隐藏动画时长(毫秒)。 |
| overlay | boolean | 否 | false | 是否显示全局遮罩层。 |
| showText | boolean | 否 | true | 触发器是否显示颜色文本值。 |
复杂 Props 示例
swatchColors:
const mySwatches = [
'#FF0000',
'rgba(0, 255, 0, 0.5)',
'linear-gradient(90deg, #000 0%, #fff 100%)' // 支持渐变预设
];4. Emit 事件说明
| 事件名 | 回调参数 | 触发时机 |
|:-------|:---------|:---------|
| update:modelValue | (value: string) | 当颜色发生任何变化时实时触发(拖拽、输入、点击预设)。 |
| change | (value: string) | 当颜色选择面板关闭时触发。通常用于提交最终选择结果。 |
| clear | () | 点击清除按钮时触发。 |
5. 使用指南
基础使用
<script setup lang="ts">
import { ref } from 'vue';
import { DpColorPicker } from 'dp-color-picker';
import 'dp-color-picker/dist/dp-color-picker.css'; // 引入样式
const color = ref('#4096ff');
const handleChange = (val: string) => {
console.log('最终选择颜色:', val);
};
</script>
<template>
<DpColorPicker
v-model="color"
@change="handleChange"
/>
</template>高级配置
启用 RGB 格式输出并自定义最近使用记录数量:
<DpColorPicker
v-model="color"
format="RGB"
:enable-alpha="true"
:enable-recent-colors="true"
:max-count="15"
/>常见问题
Q: 渐变色字符串无法解析?
A: 组件支持标准的 CSS linear-gradient 和 radial-gradient 格式。请确保传入的字符串格式规范,例如 linear-gradient(90deg, ...) 或 radial-gradient(circle at center, ...)。
Q: 如何禁用最近使用颜色?
A: 设置 :enable-recent-colors="false" 即可隐藏该区域并停止记录。
扩展接口
组件导出了内部工具函数,可供二次开发使用:
import {
rgb2hex,
hsv2rgb,
parseGradient,
formatGradient
} from 'dp-color-picker';6. ECharts 图表颜色适配
组件提供了专门的 ECharts 渐变色转换工具函数,可以将选择器输出的 CSS 渐变字符串与 ECharts 的渐变对象格式互相转换,实现选择器与 ECharts 图表的无缝集成。
核心问题
dp-color-picker 输出的渐变色是 CSS 格式字符串:
"linear-gradient(180deg, rgba(84,112,198,0.8) 0%, rgba(84,112,198,0.05) 100%)"而 ECharts 使用自己的渐变对象格式:
{
type: 'linear',
x: 0.5, y: 0, x2: 0.5, y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(84,112,198,0.8)' },
{ offset: 1, color: 'rgba(84,112,198,0.05)' }
]
}两者方向表示方式不同:CSS 使用角度(0-360°),ECharts 使用 x/y/x2/y2 坐标对(0-1)。转换函数会自动处理这个差异。
导入方式
import {
cssGradientToECharts, // CSS 字符串 → ECharts 对象
echartsGradientToCss, // ECharts 对象 → CSS 字符串
toEChartsGradient, // GradientColor → ECharts 对象
fromEChartsGradient, // ECharts 对象 → GradientColor
} from 'dp-color-picker';
import type {
EChartsGradient,
EChartsLinearGradient,
EChartsRadialGradient,
EChartsColorStop,
} from 'dp-color-picker';API 说明
| 函数 | 参数 | 返回值 | 说明 |
|:-----|:-----|:-------|:-----|
| cssGradientToECharts | (css: string) | EChartsGradient \| null | 将 CSS 渐变字符串转为 ECharts 渐变对象。解析失败返回 null。 |
| echartsGradientToCss | (echarts: EChartsGradient) | string | 将 ECharts 渐变对象转为 CSS 渐变字符串。 |
| toEChartsGradient | (grad: GradientColor) | EChartsGradient | 将内部 GradientColor 对象转为 ECharts 渐变对象。 |
| fromEChartsGradient | (echarts: EChartsGradient) | GradientColor | 将 ECharts 渐变对象转为内部 GradientColor 对象。 |
类型定义
interface EChartsColorStop {
offset: number; // 0 ~ 1
color: string;
}
interface EChartsLinearGradient {
type: 'linear';
x: number; // 0 ~ 1,起点 X
y: number; // 0 ~ 1,起点 Y
x2: number; // 0 ~ 1,终点 X
y2: number; // 0 ~ 1,终点 Y
colorStops: EChartsColorStop[];
}
interface EChartsRadialGradient {
type: 'radial';
x: number; // 0 ~ 1,圆心 X
y: number; // 0 ~ 1,圆心 Y
r: number; // 0 ~ 1,半径
colorStops: EChartsColorStop[];
}
type EChartsGradient = EChartsLinearGradient | EChartsRadialGradient;方向转换规则
CSS 角度与 ECharts 坐标的对应关系:
| CSS 角度 | 渐变方向 | ECharts (x, y) → (x2, y2) |
|:---------|:---------|:---------------------------|
| 0deg | 下 → 上 | (0.5, 1.0) → (0.5, 0.0) |
| 90deg | 左 → 右 | (0.0, 0.5) → (1.0, 0.5) |
| 180deg | 上 → 下 | (0.5, 0.0) → (0.5, 1.0) |
| 270deg | 右 → 左 | (1.0, 0.5) → (0.0, 0.5) |
| 45deg | 左下 → 右上 | 约 (0.15, 0.85) → (0.85, 0.15) |
完整示例:折线图渐变面积
<script setup lang="ts">
import { ref, computed, onMounted, watch } from 'vue';
import * as echarts from 'echarts';
import { DpColorPicker, cssGradientToECharts } from 'dp-color-picker';
import 'dp-color-picker/dist/dp-color-picker.css';
const chartRef = ref<HTMLDivElement>();
let chart: echarts.ECharts | null = null;
// 颜色选择器绑定的 CSS 渐变字符串
const areaColor = ref('linear-gradient(180deg, rgba(84,112,198,0.8) 0%, rgba(84,112,198,0.05) 100%)');
function updateChart() {
if (!chart) return;
// 核心:将 CSS 渐变字符串转为 ECharts 渐变对象
const gradient = cssGradientToECharts(areaColor.value);
chart.setOption({
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
},
yAxis: { type: 'value' },
series: [{
type: 'line',
smooth: true,
data: [820, 932, 901, 934, 1290, 1330, 1320],
areaStyle: {
color: gradient, // 直接使用转换后的 ECharts 渐变对象
},
}],
});
}
// 颜色变化时实时更新图表
watch(areaColor, updateChart);
onMounted(() => {
if (chartRef.value) {
chart = echarts.init(chartRef.value);
updateChart();
}
});
</script>
<template>
<div style="display: flex; gap: 24px; align-items: flex-start;">
<DpColorPicker v-model="areaColor" border />
<div ref="chartRef" style="width: 600px; height: 400px;" />
</div>
</template>完整示例:柱状图渐变
<script setup lang="ts">
import { ref } from 'vue';
import * as echarts from 'echarts';
import { DpColorPicker, cssGradientToECharts } from 'dp-color-picker';
import 'dp-color-picker/dist/dp-color-picker.css';
const barColor = ref('linear-gradient(0deg, rgba(145,204,117,1) 0%, rgba(145,204,117,0.3) 100%)');
// 在构建 ECharts option 时使用
const gradient = computed(() => cssGradientToECharts(barColor.value));
const option = computed(() => ({
xAxis: { type: 'category', data: ['A', 'B', 'C', 'D'] },
yAxis: { type: 'value' },
series: [{
type: 'bar',
data: [120, 200, 150, 80],
itemStyle: {
borderRadius: [4, 4, 0, 0],
color: gradient.value, // 柱状图渐变填充
},
}],
}));
</script>完整示例:从 ECharts 配置反向加载到选择器
当你需要编辑已有的 ECharts 图表配置时,可以将 ECharts 渐变对象反向转为 CSS 字符串:
<script setup lang="ts">
import { ref } from 'vue';
import { DpColorPicker, echartsGradientToCss } from 'dp-color-picker';
import 'dp-color-picker/dist/dp-color-picker.css';
// 已有的 ECharts 渐变配置(例如从后端获取或已保存的配置)
const existingGradient = {
type: 'linear' as const,
x: 0, y: 0, x2: 0, y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(255, 0, 0, 0.8)' },
{ offset: 1, color: 'rgba(255, 0, 0, 0.1)' },
],
};
// 反向转换为 CSS 字符串,绑定到选择器
const color = ref(echartsGradientToCss(existingGradient));
// 用户修改后,再转回 ECharts 格式
import { cssGradientToECharts } from 'dp-color-picker';
// const echartsGradient = cssGradientToECharts(color.value);
</script>
<template>
<DpColorPicker v-model="color" border />
</template>多图表场景:组合使用
<script setup lang="ts">
import { ref, computed, onMounted, watch } from 'vue';
import * as echarts from 'echarts';
import { DpColorPicker, cssGradientToECharts } from 'dp-color-picker';
import 'dp-color-picker/dist/dp-color-picker.css';
const chartRef = ref<HTMLDivElement>();
let chart: echarts.ECharts | null = null;
// 分别控制折线面积和柱状图的渐变
const lineGradient = ref('linear-gradient(180deg, rgba(84,112,198,0.6) 0%, rgba(84,112,198,0.02) 100%)');
const barGradient = ref('linear-gradient(0deg, rgba(145,204,117,1) 0%, rgba(145,204,117,0.3) 100%)');
function updateChart() {
if (!chart) return;
chart.setOption({
tooltip: { trigger: 'axis' },
legend: { data: ['Revenue', 'Expenses'] },
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
},
yAxis: { type: 'value' },
series: [
{
name: 'Revenue',
type: 'line',
smooth: true,
data: [820, 932, 901, 934, 1290, 1330, 1320],
itemStyle: { color: '#5470c6' },
areaStyle: {
color: cssGradientToECharts(lineGradient.value),
},
},
{
name: 'Expenses',
type: 'bar',
data: [620, 732, 701, 734, 1090, 1130, 1120],
itemStyle: {
borderRadius: [4, 4, 0, 0],
color: cssGradientToECharts(barGradient.value),
},
},
],
});
}
watch([lineGradient, barGradient], updateChart);
onMounted(() => {
if (chartRef.value) {
chart = echarts.init(chartRef.value);
updateChart();
}
});
</script>
<template>
<div>
<div style="display: flex; gap: 16px; margin-bottom: 16px;">
<div>
<label style="font-size: 14px; color: #666;">折线面积渐变</label>
<DpColorPicker v-model="lineGradient" border />
</div>
<div>
<label style="font-size: 14px; color: #666;">柱状图渐变</label>
<DpColorPicker v-model="barGradient" border />
</div>
</div>
<div ref="chartRef" style="width: 100%; height: 400px;" />
</div>
</template>已知限制
- 径向渐变信息丢失:dp-color-picker 的径向渐变始终输出
circle at center。将 ECharts 径向渐变(含自定义 x/y/r)转为 CSS 再转回时,原始的位置和半径信息会丢失。 - 角度精度:由于
atan2浮点计算,CSS ↔ ECharts 往返转换时角度可能有 ±1° 的误差。
