react-color

react-color

react-color - npm (npmjs.com)

https://github.com/casesandberg/react-color

官网教程

React Color (casesandberg.github.io)

实操使用

// index.tsx

import React, { useState, useEffect, useCallback, useMemo } from 'react';
import {
  ColorResult,
  // BlockPicker,
  // ChromePicker,
  // CirclePicker,
  // CompactPicker,
  // GithubPicker,
  // HuePicker,
  // MaterialPicker,
  // PhotoshopPicker,
  SketchPicker,
  // SliderPicker,
  // SwatchesPicker,
  // TwitterPicker,
} from 'react-color';
import cn from 'classnames';
import { CaretDownOutlined, CaretUpOutlined } from '@ant-design/icons';
import Style from './index.module.less';

type findParentDom = {
  className: string;
  parentNode: findParentDom;
};

// 遍历查找父元素
const findParent = (item: findParentDom, value: string[]): string[] => {
  if (!item) {
    return value;
  }
  value.push(item.className);

  return findParent(item.parentNode, value);
};

type colorProps = {
  value?: string;
  only: string;
  onChange: (value: string) => void;
  width?: number; // 当前颜色预览方块长度
  [key: string]: any;
  isShort?: boolean; // 当前是否是短颜色选择器样式 默认是false
};

const ColorPicker: React.FC<colorProps> = Props => {
  const {
    value,
    only,
    onChange,
    width = 239,
    isShort = false,
    title, // 颜色标题
    ...others
  } = Props;
  const [color, setColor] = useState(value || '#fff');
  const [pickerState, setPickerState] = useState(false);

  // 调用拾色器函数
  const listenersFn = useCallback(
    e => {
      const findDom = findParent(e.target, []);
      // 2022-11-23
      // closeColorPickerWhenItOpen 选色器展开情况再次点击则关闭
      // clickColorPicker 点击到颜色选择器
      const closeColorPickerWhenItOpen =
        pickerState &&
        !findDom.some(item => String(item).search('sketch-picker') >= 0) &&
        findDom.some(item => String(item).search(only) >= 0);
      const clickColorPicker = findDom.some(
        item => String(item).search(only) >= 0
      );

      // 判断当前鼠标落点是否在颜色选择器上
      // true 展开选色器 false 关闭
      if (closeColorPickerWhenItOpen) {
        setPickerState(false);
      } else if (clickColorPicker) {
        setPickerState(true);
      } else {
        setPickerState(false);
      }
    },
    [pickerState, only]
  );

  // 控制回调
  useEffect(() => {
    document.body.addEventListener('click', listenersFn);
    return () => {
      document.body.removeEventListener('click', listenersFn);
    };
  }, [listenersFn]);

  // 拾色器change事件
  const onChangeComplete = useCallback(
    (values: ColorResult) => {
      setColor(values.hex);
      onChange(values.hex);
    },
    [onChange]
  );
  // 拾色器属性
  const pickerProps = useMemo(() => {
    // 短拾色器时,长度用CSS控制
    return isShort
      ? { color, onChangeComplete, ...others }
      : {
          color,
          onChangeComplete,
          width: String(width),
          ...others,
        };
  }, [color, isShort, onChangeComplete, others, width]);

  const rightClassName = () => {
    let className = '';
    if (pickerState) {
      className = 'colorBoxCheckedStatus';
    } else {
      className = 'colorBoxNoCheckedStatus';
    }
    return isShort ? `${className}Short` : className;
  };

  return (
    <>
      <div
        className={cn('colorBox', Style[rightClassName()], String(only))}
        {...others}
      >
        <div
          className="colorContent"
          style={{
            width,
            background: color,
          }}
        />
        <div className={isShort ? 'colorSuffix-short' : 'colorSuffix'}>
          {pickerState ? (
            <CaretDownOutlined className={Style.iconStyle} />
          ) : (
            <CaretUpOutlined className={Style.iconStyle} />
          )}
        </div>

        {pickerState && (
          <SketchPicker
            className={isShort ? Style['keep-right-color-picker'] : ''}
            {...pickerProps}
          />
        )}
      </div>
      {title && <span className={Style['color-picker-title']}>{title}</span>}
    </>
  );
};

export default ColorPicker;

// index.module.less

.colorBoxCheckedStatus {
  height: 32px;
  border-color: #2994ff !important;
  box-shadow: 0 0 0 2px rgba(0, 119, 255, 20%);
}
.colorBoxCheckedStatusShort {
  .colorBoxCheckedStatus;
  height: 24px;
}
.colorBoxNoCheckedStatus {
  height: 32px;
}
.colorBoxNoCheckedStatusShort {
  height: 24px;
}
.iconStyle {
  color: rgba(0, 0, 0, 0.45);
}
:global {
  .colorBox {
    position: relative;
    cursor: pointer;
    touch-action: manipulation;
    width: fit-content;
    display: flex;
    justify-content: space-between;
    align-items: center;
    border: 1px solid #d9d9d9;
    border-radius: 4px;
    padding: 4px;
    transition: all 0.3s;
    outline: 0;
    box-sizing: border-box;
    &:hover {
      border-color: #2994ff;
    }
  }

  .sketch-picker,
  .block-picker,
  .chrome-picker,
  .circle-picker,
  .compact-picker,
  .github-picker,
  .hue-picker,
  .material-picker,
  .photoshop-picker,
  .slider-picker,
  .swatches-picker,
  .twitter-picker {
    position: absolute;
    left: 0;
    top: 35px;
    z-index: 1;
  }
  .colorContent {
    height: 100%;
    &::after {
      content: '';
    }
  }
  .colorSuffix {
    position: absolute;
    right: 16px;
  }
  .colorSuffix-short {
    width: 16px;
    margin-left: 5px;
  }
}

.keep-right-color-picker {
  width: 230px !important;
}

.color-picker-title {
  position: relative;
  top: -26px;
  right: -64px;
}

透明度不生效的时候

  // 拾色器change事件
  const onChangeComplete = useCallback(
    (values: ColorResult) => {
      setColor(values.hex);
      onChange(values.hex);
    },
    [onChange]
  );

透明度生效的时候

      setColor(
        `rgba(${values.rgb.r},${values.rgb.g},${values.rgb.b},${values.rgb.a})`
      );
      onChange(
        `rgba(${values.rgb.r},${values.rgb.g},${values.rgb.b},${values.rgb.a})`
      );
posted @ 2022-12-06 20:55  乐盘游  阅读(188)  评论(0编辑  收藏  举报