Antd 自定义列表全选功能

背景

需要为List组件自定义全选功能,如下图所示:

在这里插入图片描述

  • 全选checkbox需要与下面每一项的checkbox联动;
  • 当从第一页翻页到第二页的时候,第一页已选的内容保持,可以对第二页勾选,同时保证全选checkbox的状态是正确的。

实现

组件一 SelectAllCheckbox.tsx:

import { Checkbox } from 'antd';
import { t } from 'i18next';
import { forwardRef, useEffect, useImperativeHandle, useState } from 'react';
import TableSelectedDes from '../TableSelectedDes';// rowId必填,跟selectedRowKeys一致
export type CheckBoxItem = { rowId: number } & Record<string, any>;interface Props {data: CheckBoxItem[]; // 当前页的数据limit?: number; // 当前页的page size,默认为20callbackSelectedRowKeys: (values: number[]) => void;
}// 根据当前页的数据,判断当前页已经被选中的项
export const getCurrentCheckedList = (allKeys: number[], currentPageData: CheckBoxItem[]) => {const current: number[] = [];allKeys?.forEach((checkedId) => {currentPageData?.forEach((c: CheckBoxItem) => {if (c.rowId === checkedId) {current.push(checkedId);}});});return current;
};function SelectAllCheckbox(props: Props, ref: any) {const { data, limit = 20, callbackSelectedRowKeys } = props;const [selectedRowKeys, setSelectedRowKeys] = useState<number[]>([]);const [indeterminate, setIndeterminate] = useState(false);const [checkAll, setCheckAll] = useState(false);// 单个checkbox被点击的时候const handleClickItemCheckbox = (isChecked: boolean, clickedId: number) => {let keys;if (isChecked) {keys = selectedRowKeys.filter((key) => key !== clickedId);} else {keys = [...selectedRowKeys, clickedId];}setSelectedRowKeys(keys);const current = getCurrentCheckedList(keys, data);const curLimit = data?.length < limit ? data?.length : limit;setCheckAll(current?.length === curLimit);setIndeterminate(!!current.length && current.length < curLimit);};// 全选checkbox被点击const handleClickAllCheckbox = () => {if (!checkAll) {setSelectedRowKeys(Array.from(new Set([...selectedRowKeys, ...(data?.map((item: CheckBoxItem) => item.rowId) || [])])),);} else {// 比如取消选择第二页的数据,但是还需要保留第一页已选择的数据setSelectedRowKeys(selectedRowKeys.filter((key) => !data?.map((item) => item.rowId)?.includes(key)));}setCheckAll(!checkAll);setIndeterminate(false);};// 取消选择const cancelSelectedAll = () => {setSelectedRowKeys([]);setIndeterminate(false);setCheckAll(false);};// 当切换页数的时候,可能需要重置当前页的全选checkbox状态const handleSetCheckAllStatus = (list: CheckBoxItem[], curLimit?: number) => {const neeLimit = curLimit || limit;const currentPageCheckedList = getCurrentCheckedList(selectedRowKeys, list);setCheckAll(currentPageCheckedList?.length === neeLimit);setIndeterminate(!!currentPageCheckedList.length && currentPageCheckedList.length < neeLimit);};// 父组件可能存在批量操作之类的,比如批量删除所选项之后,需要重新更新selectedRowKeysconst handleUpdateSelectedRowKeys = (keys: number[]) => {setSelectedRowKeys(keys);};useImperativeHandle(ref, () => ({handleClickItemCheckbox,handleSetCheckAllStatus,handleUpdateSelectedRowKeys,}));useEffect(() => {callbackSelectedRowKeys(selectedRowKeys);}, [selectedRowKeys]);return (<><Checkboxstyle={{ marginRight: 5, alignSelf: 'center' }}indeterminate={indeterminate}checked={checkAll}onChange={handleClickAllCheckbox}>{t('shark-select-all')}</Checkbox>{selectedRowKeys?.length > 0 && (<TableSelectedDes selectedRowKeys={selectedRowKeys} cancelSelected={cancelSelectedAll} />)}</>);
}/** 全选Checkbox组件* 1. 支持全选、取消选择* 2. 支持数据翻页时,checkbox正常联动*/
export default forwardRef(SelectAllCheckbox);

组件二 TableSelectedDes.tsx:

import { Button, Space } from 'antd';
import { t } from 'i18next';type Props = {selectedRowKeys: React.Key[];cancelSelected: () => void;
};export default function TableSelectedDes(props: Props) {const { selectedRowKeys = [], cancelSelected } = props;return (<Space size="middle"><p style={{ marginBottom: 0, fontSize: 12 }}>{t('shark-choosed')} {selectedRowKeys?.length} {t('shark-items')}</p><Button style={{ marginLeft: -22, fontSize: 12 }} type="link" onClick={cancelSelected}>{t('shark-deselect')}</Button></Space>);
}

使用

  // 请求数据const getMessageData = async () => {try {// const res = await xxx;if (!res.errmsg) {const newData = res.result.data?.map((item: MessageItem) => ({ ...item, rowId: item.id })); // 关键点,设置rowIdsetData(newData);setTotal(res.result.total);// 关键点// 当翻页时,初始化【全选】选项listBatchRowRef.current?.handleSetCheckAllStatus(newData);}} catch (e) {console.log(e);}};const handleClickItemCheckbox = (isChecked: boolean, clickedId: number) => {listBatchRowRef.current?.handleClickItemCheckbox(isChecked, clickedId);};const renderListItem = (item: MessageItem) => {const { sender, create_time, title, message_status } = item;const time = moment(create_time).format('YYYY-MM-DD HH:mm:ss');const description = (<Row>{time}<span style={{ marginLeft: 10 }}>{sender}</span></Row>);const isChecked = selectedRowKeys?.includes(item.rowId);return (<List.Itemactions={[<Button type="link" style={{ padding: 0 }} onClick={() => handleDetail(item)}>{t('shark-detail')}</Button>,<Button type="link" danger style={{ padding: 0 }} onClick={() => handleDelete(item)}>{t('shark-delete')}</Button>,]}>// 单个项的checkbox框<Checkboxstyle={{ marginRight: 10 }}onChange={() => handleClickItemCheckbox(isChecked, item.rowId)} // 关键点,单个项的点击checked={isChecked}onClick={(e) => e.stopPropagation()} // 阻止点击复选框时,促使折叠面板展开/折叠/><List.Item.Metatitle={<span style={{ color: message_status === MessageType.READ ? 'rgba(0, 0, 0, 0.45)' : '#000' }}>{title}</span>}description={description}/></List.Item>);};// 引用组件
<SelectAllCheckboxdata={data as unknown as CheckBoxItem[]}callbackSelectedRowKeys={setSelectedRowKeys}ref={selectAllCheckboxRef}
/>{/* 消息列表 */}
<ListitemLayout="horizontal"dataSource={data}rowKey="id"pagination={{onChange: (page) => setSearchParams({ ...searchParams, page }),pageSize: 20,current: searchParams.page,total,showTotal: () => `Total ${total} items`,}}loading={loading}className="message-tab-list-container"renderItem={renderListItem}
/>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/852525.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

当JS遇上NLP:开启图片分析的奇幻之旅

前言 在当今科技飞速发展的时代&#xff0c;JavaScript&#xff08;JS&#xff09;作为广泛应用的编程语言&#xff0c;展现出了强大的活力与无限的可能性。与此同时&#xff0c;自然语言处理&#xff08;NLP&#xff09;领域也正在经历着深刻的变革与进步。 当这两者碰撞在一…

【并发编程系列一】并发编年史:线程的双刃剑——从优势到风险的全面解析

文章目录 并发简史&#x1f5a5;️初期探索&#xff08;20世纪50-60年代&#xff09;并发理论基础&#xff08;1965年以后&#xff09;并行计算的兴起&#xff08;1970年代至1980年代&#xff09;现代并发技术&#xff08;1990年代至今&#xff09; 线程的优势&#x1f60d;发挥…

DDei在线设计器-API概述

API文档 本文档提供了DDei组件所包含的关键API接口&#xff0c;以及重要类之间的关系&#xff0c;并以可运行示例代码的形式说明API的调用&#xff0c;便于开发人员进行查阅、调试和复制。 如需了解详细的API教程以及参数说明&#xff0c;请参考DDei文档 设计器 设计器API用于…

【车载AI音视频电脑】200万像素迷你一体机

产品主要特点&#xff1a; -设备安装方便简洁&#xff0c;可通过3M胶直接将设备粘 贴到车前挡风玻璃上 -支持IE预览&#xff0c;手机&#xff0c;PAD实时预览&#xff0c; 支持电脑客 户端实时预览功能 -内置2路模拟高清, 每路均可达到200万像素。另 外可扩充2路1080P模拟…

基于springboot实现问卷调查系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现问卷调查系统演示 摘要 传统信息的管理大部分依赖于管理人员的手工登记与管理&#xff0c;然而&#xff0c;随着近些年信息技术的迅猛发展&#xff0c;让许多比较老套的信息管理模式进行了更新迭代&#xff0c;问卷信息因为其管理内容繁杂&#xff0c;管理数…

go context 源码刨析(一)

Context 上下文context.Context 是用来设置截止时间、同步信号&#xff0c;传递请求相关值的结构体。 context.Context 定义了四个需要实现的方法&#xff1a; Deadline: 返回 context.Context 被取消的时间。Done: 返回一个 Channel&#xff0c;这个 Channel 会在当前工作完…

Django 5 Web应用开发实战

文章目录 一、内容简介二、目录内容三、值得一读四、适读人群 一、内容简介 《Django 5 Web应用开发实战》集Django架站基础、项目实践、开发经验于一体&#xff0c;是一本从零基础到精通Django Web企业级开发技术的实战指南。《Django 5 Web应用开发实战》内容以Python 3.x和…

UML相关2

内容 说明 用例编号 UC-1 用例名称 客户注册 用例说明 客户参与者通过注册获得进入彬使用系统的权限 参与者 客户 前置条件 无 后置条件 系统正确接收用户信息并保存到数据库 基本路径 发布注册申请系统显示注册页面客户填写相应信息并提交注册成功后可以进行其…

1毛钱1百万token,写2遍红楼梦!国产大模型下一步还想卷什么?

大模型价格战&#xff0c;这匹国产黑马又破纪录了&#xff01;最低的GLM-4 Flash版本&#xff0c;百万token价格已经低至0.1元&#xff0c;可以说是击穿地心。MaaS 2.0大升级&#xff0c;让企业训练私有模型的成本无限降低。 刚刚&#xff0c;智谱AI开放日上&#xff0c;新一代…

QT 5.14.2 应用程序打包

我们可以直接通过开发工具预览我们的程序。但是当要把开发好的程序给别人使用的时候,我们就需要把程序打包成可执行的exe,然后把这个exe文件和其他相关的文件一起发给别人,这样别人就可以使用了。 一、生成可独立运行的exe (一)、编译程序的Release版本 1、切换编译方式为…

基于C#开发web网页管理系统模板流程-打包发布

点击返回目录-> 基于C#开发web网页管理系统模板流程-总集篇-CSDN博客 前言 本系列中&#xff0c;作为开发者我们通过ASP.net Web模板设计网页&#xff0c;网页的任何设计、源代码都是直接可见的&#xff0c;在实际应用开发中&#xff0c;显然这些都是商业、公司机密 通过打包…

【Effective Web】常见的css居中方式

CSS居中方式 水平居中 text-align:center 适用范围&#xff1a;容器中都是行内元素 缺点&#xff1a;容器内所有元素都会居中&#xff0c;如果是文本描述需要左对齐&#xff0c;需要增加text-align:left覆盖 margin: 0 auto 适用范围&#xff1a;容器宽度固定。子元素宽度…

UML精简概述

UML精简概述 UML精简概述 UML精简概述UML的定义常见的关系 在学习设计模式之前&#xff0c;需要掌握一些预备知识&#xff0c;主要包括UML类图和面向对象设计原则&#xff0c;它们是“基础内功”&#xff0c;将为后续的“深入修行”奠定基础。UML类图可用于描述每一个设计模式的…

C++ 34 之 单例模式

#include <iostream> #include <string.h> using namespace std;class King{// 公共的函数&#xff0c;为了让外部可以获取唯一的实例 public:// getInstance 获取单例 约定俗成static King* getInstance(){return true_king;}private: // 私有化// 构造函数设置为…

BL104钡铼多协议采集网关助力企业智能化转型

BL104钡铼多协议采集网关&#xff08;PLC物联网关BL104&#xff09;是为满足工业环境需求而设计的专业工业级协议转换网关。它在企业智能化转型过程中扮演着关键角色&#xff0c;为企业提供了高效、稳定的通信解决方案&#xff0c;助力企业实现智能化转型。 首先&#xff0c;P…

基于STM32和人工智能的智能家居监控系统

目录 引言环境准备智能家居监控系统基础代码实现&#xff1a;实现智能家居监控系统 4.1 数据采集模块4.2 数据处理与分析4.3 控制系统4.4 用户界面与数据可视化应用场景&#xff1a;智能家居管理与优化问题解决方案与优化收尾与总结 1. 引言 随着智能家居技术的快速发展&…

DockerCompose+Jenkins+Pipeline流水线打包Vue项目(解压安装配置Node)入门

场景 DockerComposeJenkinsPipeline流水线打包SpringBoot项目(解压安装配置JDK、Maven等)入门&#xff1a; DockerComposeJenkinsPipeline流水线打包SpringBoot项目(解压安装配置JDK、Maven等)入门-CSDN博客 以上使用流水线配置和打包springboot后台项目&#xff0c;如果要使…

开诊所的10个常见问题,欣九康为您一一解答!

开设一家诊所需要具备哪些条件&#xff1f;规定需要各种证件&#xff0c;而且医生执业满五年&#xff0c;备个案就行。听起来很简单是不是&#xff1f;但是&#xff0c;到了真正开始筹备诊所的时候&#xff0c;却是千头万绪&#xff0c;不知从何下手&#xff0c;到处都是问题&a…

C语言 | Leetcode C语言题解之第148题排序链表

题目&#xff1a; 题解&#xff1a; struct ListNode* merge(struct ListNode* head1, struct ListNode* head2) {struct ListNode* dummyHead malloc(sizeof(struct ListNode));dummyHead->val 0;struct ListNode *temp dummyHead, *temp1 head1, *temp2 head2;while…

推流工具OBS的下载使用

一、下载安装 OBS&#xff0c;windows版本官网下载地址 二、推流步骤 安装好之后&#xff0c;打开软件 1、右下角&#xff0c;打开设置 2、输入推流地址&#xff0c;一般为rtmp格式开头的推流地址 输入完成后&#xff0c;应用并确定关闭窗口 3、“来源”里面新建媒体源、新…