react-color
react-color
官网教程
实操使用
// 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})`
);
人生到处知何似,应似飞鸿踏雪泥。