这是我参与11月更文挑战的第10天,活动详情查看:2021最后一次更文挑战
TIP 👉 呜呼!楚虽三户能亡秦,岂有堂堂中国空无人!____陆游《金错刀行》
前言
Web Component是前端界一直非常热衷的一个领域,用第三方组件化的框架去实现的话,你需要依赖框架本身很多东西,很多时候我们只是简单的几个组件,不是很大,也不是很多,所以为了保证组件的`轻量,简单`,其实这个时候我们并不想采用第三方的框架。ColorPicker 颜色拾色器
import
import ColorPicker from '@/components/ColorPicker/ColorPicker';
Props
1. value
- 类型:string
- 默认值:"#999"
- 说明:颜色值
2. onChange
- 类型:func (必填)
- 默认值:无
- 说明:拾色器中点击"确定"按钮后的回调函数,入参:
- {string} color 选中的颜色值
3. className
- 类型:string | array | object(key: 样式名,value: bool)
- 默认值:无
- 说明:最外层元素样式
<ColorPicker className = {'my-class'}></ColorPicker>
<ColorPicker className = {['my-class1', 'my-class2']}></ColorPicker>
<ColorPicker className = {{'my-class1': true}}></ColorPicker>
实现ColorPicker.js
/**
* 颜色拾色器组件
*/
import React from 'react';
import PropTypes from 'prop-types';
import { SketchPicker } from 'react-color';
import Button from "@/components/Button/Button.js";
// 为保证测试用例运行,不使用webpack内置utils模块,单独引入
import utils from '../../js/common/utils/index.js';
import './colorPicker.scss';
class ColorPicker extends React.Component {
// 入参类型检查
static propTypes = {
// 颜色值,如:'#666666'
value: PropTypes.string,
/**
* 拾色器中点击"确定"按钮后的回调函数
* @param {string} color 选中的颜色值
*/
onChange: PropTypes.func.isRequired,
// 最外层元素样式
className: PropTypes.oneOfType([
PropTypes.string,
PropTypes.array,
PropTypes.objectOf(PropTypes.bool)
])
}
// 入参默认值
static defaultProps = {
value: '#999'
}
constructor(props) {
super(props);
this.state = {
color: props.value || '#999',
// 是否显示拾色器浮层
isShow : false,
// 是否开启拾色器浮层动效
animate: false
}
}
componentDidUpdate(prevProps, prevState) {
if (this.props.value && prevProps.value !== this.props.value) {
this.setState({ color: this.props.value})
}
}
// 切换显示状态
toogleShow (isShow) {
if (isShow === undefined) {
isShow = !this.state.isShow
}
this.setState({ isShow, animate: true});
if (isShow) {
setTimeout(() => this.autoSetPickerPosition(), 350)
}
};
// 为保证拾色器全部显示在窗口内,自动设置拾色器浮层的位置
autoSetPickerPosition () {
const colorPicker = this.refs.colorPicker;
const pickerBox = this.refs.pickerBox;
const winWidth = window.document.body.clientWidth;
const winHeight = window.document.body.clientHeight;
const colorPickerRect = colorPicker.getBoundingClientRect();
const colorPickerX = colorPickerRect.x;
const colorPickerY = colorPickerRect.y;
const pickerBoxRect = pickerBox.getBoundingClientRect();
const pickerBoxWidth = pickerBoxRect.width;
const pickerBoxheight = pickerBoxRect.height;
// console.log(`winWidth=${winWidth}, winHeight=${winHeight}`)
// console.log(`colorPickerX=${colorPickerX}, colorPickerY=${colorPickerY}`)
// console.log(`pickerBoxWidth=${pickerBoxWidth}, pickerBoxheight=${pickerBoxheight}`)
if (colorPickerY + pickerBoxheight > winHeight) {
pickerBox.style.top = `${winHeight - pickerBoxheight - colorPickerY - 5}px`;
}
if (colorPickerX + 20 + 5 + pickerBoxWidth > winWidth) {
pickerBox.style.left = 'auto';
pickerBox.style.right = `${20 + 5}px`;
}
}
// 处理颜色改变事件
handleChange = (value)=>{
this.setState({ color: value.hex });
};
// 处理点击"确定"事件
handleOK = ()=>{
this.toogleShow(false);
this.props.onChange && this.props.onChange(this.state.color);
};
/**
* 选择框最外层需要的class
* @returns {string}
*/
getClassName(){
return utils.clasx(this.props.className, {
'color-picker': true
});
}
/**
* 拾色器浮层的样式
* @return {string}
*/
getPickerBoxClassName () {
return utils.clasx({
'picker-box': true,
'picker-box-show': this.state.isShow,
'picker-box-hide': !this.state.isShow,
'show-animate': this.state.isShow && this.state.animate,
'hide-animate': !this.state.isShow && this.state.animate
});
}
render() {
return (
<div className={this.getClassName()} ref="colorPicker">
<div
className="color-block"
style={ { background: this.props.value } }
onClick={ () => this.toogleShow() }
/>
<div className={ this.getPickerBoxClassName() } ref="pickerBox">
<SketchPicker
disableAlpha={true}
presetColors={[]}
color={this.state.color}
onChange={this.handleChange} />
<div className="buttons-bar">
<Button onClick={() => this.toogleShow(false)}>取消</Button>
<Button type="primary" onClick={this.handleOK}>确定</Button>
</div>
</div>
</div>
);
}
}
export default ColorPicker;
样式这块就先不放了
「欢迎在评论区讨论」