用过antd,和elementui组件都知道checkbox是一个很常用的组件,之前自己一直有一个疑惑,为什么checkbox和checkboxGroup分开两个组件写呢,不能一个组件全部一次写完呢?
后面自己封装了组件才知道,组件一定要做到颗粒化,就是封装组件一定离不开高阶组件(HOC)这个是一种思想不是泛指的一个具体组件。
封装checkBox
声明需要的参数类型
declare module 'checkboxType' {
export type CheckboxOption = {
label: string;
value: string | number;
};
export type CheckboxType = {
value?: string | number | '';
children: any;
onChange?: (value: any) => void;
options?: CheckboxOption[];
sendGroundData?: (value: string | number, falg: boolean) => void;
direction?: string;
disabled?: boolean;
checkeValue?: string[] | number[] | [];
indetermiate?: boolean;
onMouseEnter?: () => void;
onMouseLeave?: () => void;
};
}
搭建checkBox dom结构
大致的布局代码如下:
<>
<span
style={
props.direction === 'vertical'
? { '--marginTop': '10.0px' }
: ({} as Record<string, any>)
}
ref={ref}
className={checkboxContent}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
>
<span
onClick={() => {
if (disabled) {
return;
}
setChecked(!checked);
setCheckboxIndetermiate(false);
sendGroundData?.(value as string | number, !checked);
}}
className={checkboxClass}
>
<input
value={value}
onChange={(e) => {
onChange?.(e);
}}
onClick={(e) => {
e.preventDefault();
}}
type="checkbox"
className="checkbox-input"
/>
<span className="checkbox-inner"></span>
</span>
<span
onClick={() => {
if (disabled) {
return;
}
setChecked(!checked);
setCheckboxIndetermiate(false);
sendGroundData?.(value as string | number, !checked);
}}
className="checkbox-text"
style={{ color: disabled ? '#00000040' : '#000000' }}
>
{props.children}
</span>
</span>
</>
这里通过点击切换class的方式实现样式转换
const [checked, setChecked] = useState(false);
const [checkboxIndetermiate, setCheckboxIndetermiate] =
useState(indetermiate);
const checkboxContent = classNames('checkbox-content');
const checkboxClass = classNames('checkbox-content-radio', [
{
'checkbox-content-checked': checked,
'checkbox-content-checked-disabled': disabled,
'checkbox-content-indeterminate': checkboxIndetermiate, //全选半选样式
},
]);
初始化回显
useEffect(() => {
if (checkeValue) {
if (checkeValue.indexOf(value) > -1) {
setChecked(true);
}
}
}, [checkeValue]);
到这一个checkbox完成了。重头戏checkboxGroup的封装
主要考虑props.children怎么与自组建的传值问题这个我在之前的文章中已经详细讲过有兴趣的同学可以去看看
import { CheckboxGroupType } from 'CheckboxGroupType';
import classNames from 'classnames';
import React, { forwardRef, useEffect, useState } from 'react';
import Checkbox from '../Checkbox/index';
const CheckboxGroup: React.FC<CheckboxGroupType> = forwardRef(
(props, ref: any) => {
const { onChange, value, options, children } = props;
const [checkdArr, setCheckedArr] = useState<string[] | number[] | []>([]);
const sendGroundData = (value: string | number, falg: boolean) => {
console.log(value);
const arr = [...checkdArr, value as string | number].filter(
(item): boolean => {
if (!falg && item === value) {
return false;
} else {
return true;
}
},
);
setCheckedArr(arr as string[] | number[]);
};
const checkboxClassName = classNames('checkbox-group-content', {
[`checkbox-group-${props.direction}`]: props.direction,
});
useEffect(() => {
onChange?.(checkdArr);
}, [checkdArr]);
return (
<>
<div ref={ref} className={checkboxClassName}>
{ React.Children.map(children, (child) => {
return React.cloneElement(child, {
checkeValue: value ? value : [],
sendGroundData: sendGroundData,
direction: props.direction,
options:options
});
})}
</div>
</>
);
},
);
export default CheckboxGroup;
CheckboxGroup.defaultProps = {
direction: 'flex',
};
组件封装更多的还是考虑的所有影响组件后续的情况能否考虑得到,其次就是技术的实现问题了。
一个完整的checkBox完成了!
因篇幅问题不能全部显示,请点此查看更多更全内容