在React项目中实现仿饿了么Checkbox多选按钮样式的效果组件
「这是我参与2022首次更文挑战的第2天,活动详情查看:2022首次更文挑战」
前言
这是2022年的第二次更文,以前我不喜欢记录工作中遇到的一些问题,总觉得自己的脑容量可以记住所有,可事与愿违,最终还是逃不过一看就会一做就废的结果。现在觉得很有必要将工作中遇到的问题和思考加以总结,并输出成文,给今后的工作留下记录避免再次踩坑。
好了,今天要说的是:如何封装一个可多选的按钮组件?
万物皆有源,需求不可能凭空产生,肯定是有人遇到或者使用过的这样一个类似的组件,觉得可以适用于我们业务需求中,所以不可置否的他带走需求走来了(没有一个需求是简单的)。
需求背景
由于我们在工作中一开始使用的是Vue
技术栈进行开发,对应的UI框架自然选择的是Element UI
框架,所以在后来将技术栈改为React
时,选择的UI框架Antd
中有部分组件效果没有提供。比如:Element
的Checkbox多选框组件提供了按钮样式的多选效果组件,但是Antd
没有提供,那怎么办咯,现成的没有那就只有自己开发一个组件并提供给组内的小伙伴调用。
开发
搞就搞嘛,弄就完了!先来看UI设计图,知己知彼方能游刃有余:
思考:它是作为查询条件,那我们要考虑编写的组件要怎么才能放在Form表单里面使用?那就是让组件成为受控组件,这样就能契合的配合Form一起使用,减少其他开发时间。
受控组件:在React中,可变状态通常保存在组件的状态属性中,并且只能使用 setState() 更新,而呈现表单的React组件也控制着在后续用户输入时该表单中发生的情况,这种由React控制的输入表单元素而改变其值的方式,称为受控组件。
非受控组件:表单数据由DOM本身处理。即不受setState()
的控制,与传统的HTML表单输入相似,input输入值即显示最新值(使用 ref
从DOM获取表单值)。
既然已经想得足够清楚,那应该没有啥问题,赶紧开搞开搞!
创建ReactCheckBox.tsx
文件:
import React from 'react';
import './style.less'
// 默认专业
const List: any[] = [
{id: 1, value: '建筑', label: '建'},
{id: 2, value: '结构', label: '结'},
{id: 3, value: '给排水', label: '水'},
{id: 4, value: '电气', label: '电'},
{id: 5, value: '暖通', label: '暖'}
]
interface Data {
value: string | number;
label: string;
isActive?: boolean;
}
interface ReactCheckBoxProps {
data?: Data[]; // 父组件传入的数据源,若无则使用majorList数据
value?: any[]; // 选中的值
size?: string; // 尺寸大小
onChange?: (checkList: any[], checked: boolean) => void; // change函数
}
/**
* React多选组件
* props
* @constructor
*/
const ReactCheckBox = (props: ReactCheckBoxProps) => {
const {data = List, value = [], size = 'default', onChange = (checkList: any[]) => {}} = props;
/**
* 选中事件
* @param value
* @param checked
*/
const checkItem = (val: string, checked: boolean) => {
let newCheckedList:any[] = [...value];
newCheckedList = checked ? [...newCheckedList, val] : newCheckedList.filter(v => v != val);
onChange(newCheckedList, true);
}
return (
<div className={["bit-group-wrap", size].join(' ')}>
{data.map((item: any, index: number) =>
<div
className={
[
"bit-group-item",
value.includes(item.value) ? 'is-checked' : '',
item.isActive ? "is-actived" : ''
].join(' ')
}
onClick={() => checkItem(item.value, !value.includes(item.value))}
key={index}
>
{item.label}
</div>
)}
</div>
)
}
export default ReactCheckBox;
创建style.less
样式文件:
.bit-group-wrap {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
height: 30px;
.bit-group-item {
line-height: 1;
font-weight: 500;
white-space: nowrap;
vertical-align: middle;
cursor: pointer;
background: #fff;
border: 1px solid #dcdfe6;
border-left: 0;
color: #606266;
-webkit-appearance: none;
text-align: center;
box-sizing: border-box;
outline: none;
margin: 0;
transition: all .3s cubic-bezier(.645, .045, .355, 1);
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
padding: 8px 20px;
font-size: 14px;
border-radius: 0;
}
.bit-group-item:first-child {
border-left: 1px solid #dcdfe6;
}
.is-checked {
color: #fff;
background-color: #409eff;
border-color: #409eff;
box-shadow: -1px 0 0 0 #8cc5ff;
}
.is-checked:first-child {
border-left-color: #409eff;
}
.is-actived {
color: #5D5D5D;
background-color: #E3E6EE;
border-color: rgba(0, 0, 0, .15);
box-shadow: -1px 0 0 0 rgba(0, 0, 0, .15);
}
}
.small {
height: 24px;
}
.default {
height: 30px;
}
.large {
height: 40px;
}
至此,组件的相关代码也已编写完毕,可以看出代码结构和逻辑不是很复杂,就是多选功能加复选样式的结合。代码中增加了value
和onChange
的属性,这是为了让组件支持在Form表单
里面去使用,使之成为一个受控组件。
使用方法:
1)导入组件:
import ReactCheckBox from "../../../component/ReactCkeckBox/ReactCheckBox";
2)使用组件:
const List: any[] = [
{value: 1, label: '一般'},
{value: 2, label: '重要'},
{value: 3, label: '重大'}
]
<Form form={form}>
<Form.Item label="专业:" name="majors" initialValue={['建筑', '结构', '电气', '暖通']}>
<ReactCheckBox />
</Form.Item>
<Form.Item label="任务等级:" name="levels" initialValue={[1, 2]}>
<ReactCheckBox data = {List} />
</Form.Item>
</Form>
const monthList: any[] = [
{value: '2021-09-17 00:00:00', label: '9月', isActive: false},
{value: '2021-10-17 00:00:00', label: '10月', isActive: false},
{value: '2021-11-17 00:00:00', label: '11月', isActive: false},
{value: '2021-12-17 00:00:00', label: '12月', isActive: false},
{value: '2022-01-17 00:00:00', label: '1月', isActive: true},
{value: '2022-02-17 00:00:00', label: '2月', isActive: true},
{value: '2022-03-17 00:00:00', label: '3月', isActive: false},
{value: '2022-04-17 00:00:00', label: '4月', isActive: false},
{value: '2022-05-17 00:00:00', label: '5月', isActive: false},
]
<Form form={tableForm}>
<Form.Item label="客户任务时间分布:" name="filterMonth">
<ReactCheckBox
onChange={() => {
// 统计埋点
report.emit({actionId: 'xxxxx', action: ''})
}}
data={monthList}/>
</Form.Item>
<Form form={form}>
实现效果:
API:
参数 | 说明 | 类型 |
---|---|---|
data | 数据源 | any[] |
size | 尺寸大小 | small/default/large |
value | 指定选中的选项 | string[] |
onChange | 变化时回调函数 | function(checkList: any[], checked: boolean) |
万事开头难,其实需求在没有现有组件支持的情况下,组内的小伙伴就会主观的去认为有一定难度,但只要经过深思熟虑之后就会柳暗花明。仿饿了么多选按钮样式组件还可以继续优化迭代,在NPM
上已经有相应的包供别人使用,但是还不够足够复用,后续会进行迭代升级更新版本,让其拥有更好地适用性。
往期精彩文章
后语
伙伴们,如果觉得本文对你有些许帮助,点个👍或者➕个关注在走呗^_^ 。另外如果本文章有问题或有不理解的部分,欢迎大家在评论区评论指出,我们一起讨论共勉。
转载自:https://juejin.cn/post/7054806424853381128