常用二次封装Ant-design组件(1)--- CheckBox

本文详细描述了如何在AntDesign库5.2.3版本中封装Checkbox和CheckGroup组件,以满足设计稿中的集成功能需求,旨在提高开发者的开发效率。作者分享了代码实现和使用示例,包括自定义选项和处理确认回调的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

废话文学:一年没怎么更新过文章了,在忙着荒野求生(换了work+摸鱼)。但是,最近在工作的时候看到设计稿里的集成功能熟悉又陌生(其实就是包含了组件,然后组件又达不到这个要求),然后出现的频率还挺高的,先记录一下(二开倒是没什么难度,也不复杂,就是会浪费点开发时间),这里只针对Antd封装(版本^5.2.3),找个时间发个包,提高开发效率。

设计稿需求效果

解析:就是对CheckBox组件和CheckGroup的封装复用,具体功能还是根据需求文档来吧

组件代码(ts)

import { Button, Checkbox, Col, Popover, Row } from 'antd'
import styles from "./index.less"
import React, { useEffect, useState } from 'react'
import { CheckboxValueType } from 'antd/es/checkbox/Group';
import {
	SettingOutlined
} from '@ant-design/icons';

interface boxProps {
	boxOptions?: { label: string, value: CheckboxValueType }[]	 //所有指标
	defaultCheckedList: CheckboxValueType[]	 //上次选择之后记录的指标
	onFinished: (e: CheckboxValueType[]) => void  //确认
	type: "link" | "button",
	isTitle?: boolean    //是否有副标题
	listOptions?: {
		title: string;
		valueOptions: {
			label: string;
			value: CheckboxValueType;
		}[];
	}[]   //标题+value入参   istitle为true的时候传这个  不传boxOptions
}

export default function CheckBoxGroup({ defaultCheckedList, boxOptions = [], onFinished, type = "button", isTitle = false, listOptions = [] }: boxProps) {
	const [open, setOpen] = useState(false)
	const [checkedList, setCheckedList] = useState<CheckboxValueType[]>(defaultCheckedList);
	const [allOptions, setAllOptions] = useState<CheckboxValueType[]>([])

	const Operation = {
		"button": < Button onClick={() => setOpen(true)} id='groupCheckbox' type='primary' style={{ width: "113px", fontSize: "12px", padding: "4px 7px" }}> 选择数据指标({checkedList.length})</Button >,
		"link": <Button onClick={() => setOpen(true)} id='groupCheckbox' type='link' style={{ width: "113px", fontSize: "14px", padding: "4px 7px" }} icon={<SettingOutlined />}>列表配置</Button>
	}

	useEffect(() => {
		// 是否有副标题
		if (isTitle) {
			let new_allOptions: any = []
			listOptions.forEach(item => {
				item.valueOptions.forEach((ele) => {
					new_allOptions.push(ele.value)
				})
			})
			setAllOptions(new_allOptions)
		} else {
			// allOptions
			let new_allOptions: any[] = []
			boxOptions.map(item => new_allOptions.push(item.value))
			setAllOptions(new_allOptions)
		}
	}, [])

	const checkAll = allOptions.length === checkedList.length;
	const indeterminate = checkedList.length > 0 && checkedList.length < allOptions.length;


	const onGroupChange = (list: CheckboxValueType[]) => {
		setCheckedList(list);
	}

	const onCheckAllChange = (e: any) => {
		setCheckedList(e.target.checked ? allOptions : []);
	};

	// 确认
	const onConfirm = () => {
		// console.log(checkedList);
		setOpen(false)
		onFinished(checkedList)
	}

	// 取消
	const onCancel = () => {
		setCheckedList(defaultCheckedList)
		setOpen(false)
	}

	return (
		<Popover
			placement="bottomRight"
			trigger={"click"}
			overlayClassName={styles.checkPopover}
			destroyTooltipOnHide={true}
			open={open}
			title={
				<div style={{ display: "flex", alignItems: "center", marginBottom: 0, fontWeight: "normal" }}>
					<Checkbox indeterminate={indeterminate} onChange={onCheckAllChange} checked={checkAll}>
						全选
					</Checkbox >
					<div style={{ color: "#c2c2c2" }}>(<span style={{ color: "#666FFF" }}>{checkedList.length}</span> / {allOptions.length}已选)</div>
					<Button type='link' onClick={() => setCheckedList([])}>重置</Button>
				</div>
			}
			content={
				<>
					<Checkbox.Group value={checkedList} style={{ width: '100%' }} onChange={onGroupChange}>
						{!isTitle
							?
							<Row>
								{(boxOptions || []).map(item => {
									return <Col span={8} style={{ marginTop: "8px" }}>
										<Checkbox value={item.value}>{item.label}</Checkbox>
									</Col>
								})}
							</Row>
							:
							listOptions.map(item => {
								return <div style={{ display: "flex", width: "100%" }}>
									<div style={{ width: "70px", marginTop: "8px" }}>{item.title}:</div>
									<Row style={{ width: "calc(100% - 70px)" }}>
										{(item.valueOptions || []).map(ele => {
											return <Col span={8} style={{ marginTop: "8px" }}>
												<Checkbox value={ele.value}>{ele.label}</Checkbox>
											</Col>
										})}
									</Row>
								</div>
							})
						}
					</Checkbox.Group>
					<div style={{ direction: "rtl", marginTop: "10px" }}>
						<Button type='primary' style={{ marginLeft: 10 }} onClick={() => onConfirm()}>确定</Button>
						<Button onClick={() => onCancel()}>取消</Button>
					</div>
				</>
			}
			arrow={false} >
			{Operation[type]}
		</Popover >
	)
}

less样式代码

.checkPopover {
  height: auto;
  width: 436px;
  background-color: #ffffff;
  border: 1px solid rgba(229, 229, 229, 0.3);
  box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.15);
  :global {
    .ant-popover-title {
      border-bottom: 1px solid #e5e5e5;
    }
  }
}

组件的使用

封装了一个type属性,来切换触发的形态变体,可以根据需求再加自己想要的样式

设置了两种入参,因为传入的类型有点出入加上ts类型处理比较麻烦,就没做统一入参,在需要子标题区分选择时,isTitle为true,入参用listOptions,默认为false,入参为boxOptions

完成回调的结果,我只保留的value(具体保留什么格式可以根据服务端入参来写,value无非就是需要再处理),复杂处理建议放在外级处理,如果入参也需要区分标题入参,那就在onConfirm里筛选或者onfinished去筛选也行,这个可以根据不同需求大佬们自己改动。

入参示例 1

	const allOptions = [
		{ label: "A", value: "A" },
		{ label: "B", value: "B" },
		{ label: "C", value: "C" },
		{ label: "D", value: "D" },
		{ label: "E", value: "E" },
		{ label: "F", value: "F" },
	];  //所有指标
	const defaultCheckedList = ['A', 'B', 'C'];  //上次选择之后记录的指标

	<CheckBoxGroup
		type="link"
		boxOptions={allOptions}
		defaultCheckedList={defaultCheckedList}
		onFinished={(e) => {
		console.log(e);
		}}
	/>

入参示例 2

	const list = [
		{
			title: "经营概览", valueOptions: [
				{ label: "A", value: "A" },
				{ label: "B", value: "B" },
				{ label: "C", value: "C" },
				{ label: "G", value: "G" }
			]
		},
		{
			title: "园区详情", valueOptions: [
				{ label: "D", value: "D" },
				{ label: "E", value: "E" },
				{ label: "F", value: "F" },
			]
		}
	]  //所有指标

	const defaultCheckedList = ['A', 'B', 'C'];  //上次选择之后记录的指标

	<CheckBoxGroup
		type="link"
		isTitle={true}
		listOptions={list}
		defaultCheckedList={defaultCheckedList}
		onFinished={(e) => {
		console.log(e);
		}}
	/>

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值