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

相关推荐
by__csdn1 小时前
Vue3响应式系统详解:ref与reactive全面解析
前端·javascript·vue.js·typescript·ecmascript·css3·html5
渴望成为python大神的前端小菜鸟1 小时前
react 面试题
前端·react.js·前端框架·react·面试题
Greatlifeee1 小时前
基于vue3+ts的前端网页,实现网页点击按钮打开本地exe运行文件的完整实例
前端
漏洞文库-Web安全1 小时前
CTFHub XSS通关:XSS-过滤关键词 - 教程
前端·安全·web安全·okhttp·网络安全·ctf·xss
chilavert3181 小时前
技术演进中的开发沉思-231 Ajax:页面内容修改
开发语言·前端·javascript
一只小bit1 小时前
Qt 信号与槽:信号产生与处理之间的重要函数
前端·c++·qt·cpp·页面
m0_376137941 小时前
DevUI主题系统进阶:CSS-in-JS与暗黑模式无缝切换架构
javascript·css·架构·devui
nono牛1 小时前
30天Shell脚本编程实战(14天逆袭)
前端·chrome·bash