uniapp: 如何实现圆盘/色盘取色器组件

在uniapp中如何实现一个圆盘/色盘取色器组件?需要支持用户在圆盘上滑动选取颜色,并能实时返回选中的色值。目前尝试过使用canvas绘制,但遇到触摸事件不灵敏和性能问题,是否有更优方案或现成的组件推荐?最好能兼容H5和小程序平台。

2 回复

使用<canvas>绘制圆盘,监听touchmove事件获取坐标,计算角度和饱和度。用hslrgb获取颜色值,通过$emit返回选中色值。可结合uview等UI库简化开发。


在 UniApp 中实现圆盘/色盘取色器组件,可以通过 Canvas 绘制色盘,并监听触摸事件获取颜色值。以下是实现步骤和示例代码:

实现思路

  1. 使用 Canvas 绘制色盘(HSV 色环)。
  2. 监听触摸事件,获取触摸点坐标。
  3. 计算坐标对应的颜色值(HSV 转 RGB)。
  4. 返回选中的颜色值。

示例代码

<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>

使用说明

  1. 将代码保存为 Vue 组件。
  2. 在页面中引入并使用该组件。
  3. 触摸色盘即可选择颜色,选中的颜色会显示在下方方块中。

注意事项

  • 需要调整 Canvas 位置计算(getColorAtPosition 中的 y 偏移)。
  • 可根据需求添加亮度控制或透明度功能。
  • 在真机上测试触摸事件的准确性。

这样就能在 UniApp 中实现一个基本的圆盘取色器组件了。

回到顶部