react的组件库antd design表格多选,删除的基础示例

javascript 复制代码
import React, { useState } from "react";
import { Flex, Space, Table, Tag, Button, Modal } from 'antd';
import type { TableProps } from 'antd';
import { ExclamationCircleFilled } from '@ant-design/icons';

// 解构出 Modal 的 confirm 方法,用于显示确认对话框
const { confirm } = Modal;

// 定义表格数据的类型接口
interface DataType {
  key: string;
  name: string;
  age: number;
  address: string;
  tags: string[];
  isPublished: boolean; // 是否发布状态
}

// 定义行选择的类型,便于 TypeScript 类型推断
type TableRowSelection = TableProps<DataType>['rowSelection'];

/**
 * 表格列配置工厂函数
 * 接收 onDelete 回调作为参数,实现列内的操作交互
 */
const columns = (onDelete: (key: string) => void): TableProps<DataType>['columns'] => [
  {
    title: '姓名',
    dataIndex: 'name',
    key: 'name',
    render: (text) => <a>{text}</a>,
  },
  {
    title: '是否发布',
    dataIndex: 'isPublished',
    // 注意:这里没有写 dataIndex,使用 render 的第一个参数直接接收该行的 isPublished 值
    render: (isPublished: boolean) => (
      <Tag color={isPublished ? 'green' : 'red'}>
        {isPublished ? '已发布' : '未发布'}
      </Tag>
    ),
  },
  {
    title: '答卷',
    dataIndex: 'age',
    key: 'age',
  },
  {
    title: '创建时间',
    dataIndex: 'address',
    key: 'address',
  },
  {
    title: 'Tags',
    key: 'tags',
    dataIndex: 'tags',
    render: (_, { tags }) => (
      <Flex gap="small" align="center" wrap>
        {tags.map((tag) => {
          // 根据 tag 的内容动态设置颜色
          let color = tag.length > 5 ? 'geekblue' : 'green';
          if (tag === 'loser') {
            color = 'volcano';
          }
          return (
            <Tag color={color} key={tag}>
              {tag.toUpperCase()}
            </Tag>
          );
        })}
      </Flex>
    ),
  },
  {
    title: 'Action',
    key: 'action',
    render: (_, record) => (
      <Space size="middle">
        <a>Invite {record.name}</a>
        {/* 点击删除触发回调,传入当前行的 key */}
        <a onClick={() => onDelete(record.key)}>Delete</a>
      </Space>
    ),
  },
];

// 初始数据源
const initialData: DataType[] = [
  {
    key: '1',
    name: 'John Brown',
    age: 32,
    address: 'New York No. 1 Lake Park',
    tags: ['nice', 'developer'],
    isPublished: true,
  },
  {
    key: '2',
    name: 'Jim Green',
    age: 42,
    address: 'London No. 1 Lake Park',
    tags: ['loser'],
    isPublished: false,
  },
  {
    key: '3',
    name: 'Joe Black',
    age: 32,
    address: 'Sydney No. 1 Lake Park',
    tags: ['cool', 'teacher'],
    isPublished: true,
  },
  {
    key: '4',
    name: 'Alice Smith',
    age: 28,
    address: 'Paris No. 5 River Street',
    tags: ['creative', 'designer'],
    isPublished: false,
  },
];

const Stat: React.FC = () => {
  // 1. 状态定义
  // 选中的行 keys (受控组件)
  const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
  // 表格数据源 (用于动态删除更新)
  const [tableData, setTableData] = useState<DataType[]>(initialData);

  /**
   * 2. 处理行选择变化
   * 当用户勾选/取消勾选复选框时,更新 selectedRowKeys 状态
   */
  const onSelectChange = (newSelectedRowKeys: React.Key[]) => {
    console.log('selectedRowKeys changed: ', newSelectedRowKeys);
    setSelectedRowKeys(newSelectedRowKeys);
  };

  // 3. rowSelection 配置对象
  const rowSelection: TableRowSelection = {
    selectedRowKeys, // 指定选中项的 key 数组
    onChange: onSelectChange, // 选中项发生变化时的回调
  };

  // 辅助变量:判断是否有选中项
  const hasSelected = selectedRowKeys.length > 0;

  /**
   * 4. 单行删除处理函数
   * @param key - 要删除的行的唯一 key
   */
  const handleDelete = (key: string) => {
    showDeleteConfirm(() => {
      // 过滤掉指定 key 的数据
      const newData = tableData.filter(item => item.key !== key);
      setTableData(newData);
      
      // 修复:如果被删除的行正处于选中状态,需要从选中列表中移除,避免数据不一致
      const newSelectedRowKeys = selectedRowKeys.filter(selectedKey => selectedKey !== key);
      setSelectedRowKeys(newSelectedRowKeys);
    });
  };

  /**
   * 5. 批量删除处理函数
   * 删除所有选中的行
   */
  const handleBulkDelete = () => {
    showDeleteConfirm(() => {
      // 过滤掉所有在 selectedRowKeys 中的数据
      const newData = tableData.filter(item => !selectedRowKeys.includes(item.key));
      setTableData(newData);
      // 清空选中状态
      setSelectedRowKeys([]);
    });
  };

  /**
   * 6. 通用的确认弹窗
   * @param onOk - 用户点击确认后的回调函数
   */
  const showDeleteConfirm = (onOk: () => void) => {
    confirm({
      title: '确认删除',
      icon: <ExclamationCircleFilled />,
      content: '确定要删除选中的项目吗?此操作不可恢复',
      okText: '确认',
      okType: 'danger', // 确认按钮显示为危险(红色)样式
      cancelText: '取消',
      onOk() {
        onOk(); // 执行传入的删除逻辑
      },
      onCancel() {
        console.log('取消删除');
      },
    });
  };

  return (
    <>
      {/* 顶部操作栏 */}
      <div style={{ marginBottom: 16 }}>
        {/* 批量删除按钮:当没有选中项时禁用 */}
        <Button 
          type="primary" 
          disabled={!hasSelected}
          onClick={handleBulkDelete}
          style={{ marginRight: 8 }}
        >
          批量删除
        </Button>
        {/* 显示选中数量的提示 */}
        {hasSelected && <span>已选中 {selectedRowKeys.length} 项</span>}
      </div>
      
      {/* 表格主体 */}
      <Table<DataType>
        rowSelection={rowSelection} // 注入复选框配置
        columns={columns(handleDelete)} // 注入列配置,并传递删除回调
        dataSource={tableData} // 使用 state 管理的数据源
        pagination={{ pageSize: 10 }} // 分页配置
      />
    </>
  );
};

export default Stat;

📖 代码逻辑解读

这段代码实现了一个具备数据交互能力的表格,核心逻辑可以分为以下 4 层:

1. 数据层

initialData: 定义了表格的初始数据。

tableData: 使用 useState 将初始数据变为可变状态。这是为了支持删除操作后,界面能实时更新。

selectedRowKeys: 专门用于存储当前被勾选的行的 key。Ant Design 的表格是受控组件,必须通过这个 state 来控制复选框的勾选状态。

  1. 视图层

columns: 这是一个函数,接收 onDelete 回调。这样做的好处是让列配置(Column)能够触发外部的函数(解耦)。

rowSelection: 配置了复选框的行为。它绑定了 selectedRowKeys 和 onSelectChange,实现了"勾选更新状态,状态更新视图"的闭环。

  1. 交互层 (核心)

单行删除 (handleDelete):

点击 "Delete" 链接。

触发 showDeleteConfirm。

确认后,通过 filter 过滤掉对应数据,并更新 tableData。

关键点:如果删除的是已选中的行,同步更新 selectedRowKeys,防止状态残留。

批量删除 (handleBulkDelete):

点击顶部的 "批量删除" 按钮。

利用 selectedRowKeys 数组,过滤掉所有选中的数据。

执行删除后,清空 selectedRowKeys。

  1. 体验层

Modal.confirm: 使用了 Ant Design 的确认框,防止用户误删数据。

hasSelected: 控制 "批量删除" 按钮的可用状态。如果没有勾选任何行,按钮置灰且无法点击,提升了用户体验。

相关推荐
A24207349307 分钟前
深入浅出理解AJAX:核心原理与POST/GET区别详解
前端·ajax·okhttp
LYFlied12 分钟前
【每日算法】LeetCode 300. 最长递增子序列
前端·数据结构·算法·leetcode·职场和发展
张较瘦_22 分钟前
前端 | 代码可读性 + SEO 双提升!HTML 语义化标签实战教程
前端·html
似水流年QC30 分钟前
前端国际化实战指南:i18n 工程化最佳实践总结
前端
GISer_Jing31 分钟前
企业级前端脚手架:原理与实战指南
前端·前端框架
非凡ghost36 分钟前
Floorp Browser(基于Firefox火狐浏览器)
前端·windows·学习·firefox·软件需求
hpz122339 分钟前
XHR和Fetch功能对比表格
前端·网络请求
我是小邵44 分钟前
【踩坑实录】一次 H5 页面在 PC 端的滚动条与轮播图修复全过程(Vue + Vant)
前端·javascript·vue.js
苹果电脑的鑫鑫1 小时前
Css画圆弧的方法
前端·css
2501_946230981 小时前
Cordova&OpenHarmony外观主题设置
android·javascript