You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为基于react-color的颜色选择器添加屏幕取色功能

基于react-color添加屏幕取色功能的实现方案

核心思路

无需依赖仅能在审查元素中使用的工具,直接通过浏览器原生的屏幕捕获API结合Canvas实现跨页面取色,同时用React状态管理切换两种取色模式(普通取色/屏幕取色)。

具体实现步骤

1. 模式切换UI改造

  • 在现有react-color组件外层添加切换按钮,通过React状态isScreenPickMode控制显示普通取色面板或屏幕取色遮罩。
  • 切换时隐藏原react-color取色器,显示全屏取色遮罩层。

2. 屏幕取色核心逻辑实现

使用浏览器的navigator.mediaDevices.getDisplayMediaAPI捕获屏幕流,将流绘制到Canvas,再通过Canvas的getImageData获取鼠标点击位置的像素颜色值。

以下是完整组件代码示例:

import React, { useState, useRef, useEffect } from 'react';
import { SketchPicker } from 'react-color';

const ColorPickerWithScreenPick = () => {
  const [color, setColor] = useState('#ffffff');
  const [isScreenPickMode, setIsScreenPickMode] = useState(false);
  const canvasRef = useRef(null);
  const videoRef = useRef(null);

  // 启动屏幕捕获流
  const startScreenCapture = async () => {
    try {
      const stream = await navigator.mediaDevices.getDisplayMedia({
        video: { displaySurface: 'monitor' }
      });
      videoRef.current.srcObject = stream;
      videoRef.current.play();
    } catch (err) {
      console.error('屏幕捕获授权失败:', err);
      setIsScreenPickMode(false);
    }
  };

  // 点击Canvas获取像素颜色
  const handleColorPick = (e) => {
    const canvas = canvasRef.current;
    const ctx = canvas.getContext('2d');
    const rect = canvas.getBoundingClientRect();
    const x = e.clientX - rect.left;
    const y = e.clientY - rect.top;
    const pixelData = ctx.getImageData(x, y, 1, 1).data;
    // 转成十六进制颜色
    const hexColor = `#${((1 << 24) + (pixelData[0] << 16) + (pixelData[1] << 8) + pixelData[2]).toString(16).slice(1)}`;
    setColor(hexColor);
    // 退出取色模式并停止屏幕流
    setIsScreenPickMode(false);
    const stream = videoRef.current.srcObject;
    stream.getTracks().forEach(track => track.stop());
  };

  // 视频流播放后持续绘制到Canvas
  useEffect(() => {
    if (!isScreenPickMode) return;
    startScreenCapture();
    const video = videoRef.current;
    const canvas = canvasRef.current;
    const ctx = canvas.getContext('2d');

    const drawFrame = () => {
      if (!video.paused && !video.ended) {
        ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
        requestAnimationFrame(drawFrame);
      }
    };

    video.addEventListener('play', drawFrame);
    // 清理函数:停止流并移除监听
    return () => {
      video.removeEventListener('play', drawFrame);
      const stream = video.srcObject;
      if (stream) stream.getTracks().forEach(track => track.stop());
    };
  }, [isScreenPickMode]);

  return (
    <div className="color-picker-wrapper">
      <button onClick={() => setIsScreenPickMode(!isScreenPickMode)}>
        {isScreenPickMode ? '退出屏幕取色' : '切换到屏幕取色'}
      </button>
      
      {/* 普通取色模式:显示react-color组件 */}
      {!isScreenPickMode && (
        <SketchPicker 
          color={color} 
          onChange={(newColor) => setColor(newColor.hex)} 
        />
      )}

      {/* 屏幕取色模式:显示全屏Canvas */}
      {isScreenPickMode && (
        <div className="screen-pick-overlay">
          <video ref={videoRef} style={{ display: 'none' }} />
          <canvas
            ref={canvasRef}
            width={window.innerWidth}
            height={window.innerHeight}
            onClick={handleColorPick}
            style={{ 
              position: 'fixed', 
              top: 0, 
              left: 0, 
              zIndex: 9999, 
              cursor: 'crosshair' 
            }}
          />
        </div>
      )}

      {/* 颜色预览 */}
      <div 
        className="color-preview"
        style={{ 
          width: '40px', 
          height: '40px', 
          marginTop: '10px', 
          backgroundColor: color,
          border: '1px solid #ccc'
        }}
      />
    </div>
  );
};

export default ColorPickerWithScreenPick;

3. 关键注意事项

  • 屏幕捕获需要用户手动授权,需处理授权失败的降级逻辑。
  • 该功能仅支持HTTPS环境或localhost(开发环境),部分浏览器会限制HTTP环境下的屏幕捕获。
  • 取色完成后必须停止屏幕流,避免占用系统资源。

内容的提问来源于stack exchange,提问作者Eric

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 12:10:37