uniapp: 如何实现圆盘/色盘取色器组件
在uniapp中如何实现一个圆盘/色盘取色器组件?需要支持用户在圆盘上滑动选取颜色,并能实时返回选中的色值。目前尝试过使用canvas绘制,但遇到触摸事件不灵敏和性能问题,是否有更优方案或现成的组件推荐?最好能兼容H5和小程序平台。
2 回复
使用<canvas>绘制圆盘,监听touchmove事件获取坐标,计算角度和饱和度。用hsl转rgb获取颜色值,通过$emit返回选中色值。可结合uview等UI库简化开发。
在 UniApp 中实现圆盘/色盘取色器组件,可以通过 Canvas 绘制色盘,并监听触摸事件获取颜色值。以下是实现步骤和示例代码:
实现思路
- 使用 Canvas 绘制色盘(HSV 色环)。
- 监听触摸事件,获取触摸点坐标。
- 计算坐标对应的颜色值(HSV 转 RGB)。
- 返回选中的颜色值。
示例代码
<template>
<view class="color-picker">
<canvas
canvas-id="colorPicker"
@touchstart="onTouchStart"
@touchmove="onTouchMove"
class="color-canvas"
></canvas>
<view class="selected-color" :style="{ backgroundColor: selectedColor }"></view>
</view>
</template>
<script>
export default {
data() {
return {
selectedColor: '#ff0000'
}
},
mounted() {
this.drawColorWheel()
},
methods: {
drawColorWheel() {
const ctx = uni.createCanvasContext('colorPicker', this)
const { windowWidth } = uni.getSystemInfoSync()
const size = Math.min(windowWidth * 0.8, 300)
const center = size / 2
const radius = size / 2
// 绘制 HSV 色环
for (let angle = 0; angle < 360; angle += 1) {
const startAngle = (angle - 2) * Math.PI / 180
const endAngle = angle * Math.PI / 180
ctx.beginPath()
ctx.moveTo(center, center)
ctx.arc(center, center, radius, startAngle, endAngle, false)
ctx.closePath()
const gradient = ctx.createLinearGradient(center, center, center + radius * Math.cos(startAngle), center + radius * Math.sin(startAngle))
gradient.addColorStop(0, `hsl(${angle}, 100%, 50%)`)
gradient.addColorStop(1, '#ffffff')
ctx.setFillStyle(gradient)
ctx.fill()
}
ctx.draw()
},
onTouchStart(e) {
this.getColorAtPosition(e.touches[0])
},
onTouchMove(e) {
this.getColorAtPosition(e.touches[0])
},
getColorAtPosition(touch) {
const { windowWidth } = uni.getSystemInfoSync()
const size = Math.min(windowWidth * 0.8, 300)
const center = size / 2
const radius = size / 2
const x = touch.x - (windowWidth - size) / 2
const y = touch.y - 50 // 调整画布位置偏移
// 计算距离和角度
const dx = x - center
const dy = y - center
const distance = Math.sqrt(dx * dx + dy * dy)
if (distance <= radius) {
const angle = Math.atan2(dy, dx) * 180 / Math.PI
const normalizedAngle = (angle + 360) % 360
const saturation = Math.min(1, distance / radius)
// HSV 转 RGB
this.selectedColor = this.hsvToRgb(normalizedAngle, saturation, 1)
}
},
hsvToRgb(h, s, v) {
const c = v * s
const x = c * (1 - Math.abs((h / 60) % 2 - 1))
const m = v - c
let r, g, b
if (h < 60) [r, g, b] = [c, x, 0]
else if (h < 120) [r, g, b] = [x, c, 0]
else if (h < 180) [r, g, b] = [0, c, x]
else if (h < 240) [r, g, b] = [0, x, c]
else if (h < 300) [r, g, b] = [x, 0, c]
else [r, g, b] = [c, 0, x]
const rgb = [(r + m) * 255, (g + m) * 255, (b + m) * 255]
return `rgb(${Math.round(rgb[0])}, ${Math.round(rgb[1])}, ${Math.round(rgb[2])})`
}
}
}
</script>
<style>
.color-picker {
display: flex;
flex-direction: column;
align-items: center;
padding: 20rpx;
}
.color-canvas {
width: 600rpx;
height: 600rpx;
}
.selected-color {
width: 100rpx;
height: 100rpx;
margin-top: 20rpx;
border-radius: 10rpx;
border: 2rpx solid #ccc;
}
</style>
使用说明
- 将代码保存为 Vue 组件。
- 在页面中引入并使用该组件。
- 触摸色盘即可选择颜色,选中的颜色会显示在下方方块中。
注意事项
- 需要调整 Canvas 位置计算(
getColorAtPosition中的 y 偏移)。 - 可根据需求添加亮度控制或透明度功能。
- 在真机上测试触摸事件的准确性。
这样就能在 UniApp 中实现一个基本的圆盘取色器组件了。

