react antd table可增删表格项

React组件:实现可编辑表格的增删及数据验证
该文章展示了一个React组件,用于创建可编辑表格。用户编辑每一行时即时保存数据,添加或删除表格项时统一处理。文章通过示例代码详细解释了如何维护表格数据的状态,包括添加新行时自动生成唯一索引,以及在值改变时更新数据和进行完整性检查。此外,还包含了表格列的定义和渲染方法。

区别于可编辑的表格,对于可编辑的表格,是每编辑一行,则调用接口保存数据;保存之后,再操作下一行数据。

直接增删表格项的话,是可以同时修改,之后在获取表格所有数据即可。

代码:

interface Props {
  ruleItems: TagRuleItem[];
}

export interface TagRuleItem {
  identi_path: string;
  converter: string;
  op: string;
  expected: string;
  index: number; // 需要手动添加 index, 作为每一项的唯一标识
}

function RuleTable(props: Props, ref: any) {
  const { ruleItems } = props;
  const [ruleList, setRuleList] = useState<TagRuleItem[]>(ruleItems);
  const [converterOpts, setConverterOpts] = useState<OptionType[]>([]);
  const [opOpts, setOpOpts] = useState<OptionType[]>([]);

  // 检测数据是否完整
  const checkValue = (arr: TagRuleItem[]) => {
    return arr.some((item) => {
      return Object.keys(item).some((key) => !item[key]);
    });
  };

  // 对外提供数据
  useImperativeHandle(ref, () => ({
    getTableValue: () => {
      if (checkValue(ruleList)) {
        message.error('请检查表格项是否填写完整');
        return null;
      }
      return ruleList;
    },
  }));

  // 添加表格项
  const addRuleItem = () => {
    // 以最后一项的index为基准,+1,作为新增表格项的唯一index
    const index = ruleList.length > 0 ? (ruleList[(ruleList?.length || 1) - 1]?.index || 0) + 1 : 0;
    setRuleList([
      ...ruleList,
      {
        index, // 关键点
        identi_path: '',
        converter: '',
        op: '',
        expected: '',
      },
    ]);
  };

  // 删除表格项
  const removeRuleItem = (index: number) => {
    const arrIndex = ruleList.findIndex((rule) => rule.index === index);
    if (arrIndex === -1) {
      return;
    }
    setRuleList([...ruleList.slice(0, arrIndex), ...ruleList.slice(arrIndex + 1)]);
  };

  // 监听表格项值的变化
  const onChangedRuleItem = (key: string, value: string, index: number) => {
    const ruleItem = ruleList.find((rule) => rule.index === index);
    ruleItem[key] = value; // 关键点
    setRuleList([...ruleList]); // 关键点,更新 ruleList 数据
  };

  const columns = [
    {
      title: '序号',
      dataIndex: 'index',
      render: (text: string, record: TagRuleItem, index: number) => {
        return index + 1;
      },
    },
    {
      title: '路径',
      dataIndex: 'identi_path',
      render: (text: string, record: TagRuleItem) => {
        return (
          <Space>
            <Input
              disabled={!text}
              value={text}
              onChange={(e) => onChangedRuleItem('identi_path', e.target.value, record.index)}
            />
            <SelectOutlined
              style={{
                color: '#1890ff',
              }}
              onClick={() => {}}
            />
          </Space>
        );
      },
    },
    {
      title: '转换函数',
      dataIndex: 'converter',
      render: (text: string, record: TagRuleItem) => {
        return (
          <Select
            options={converterOpts}
            value={text}
            onChange={(value) => onChangedRuleItem('converter', value, record.index)}
          />
        );
      },
    },
    {
      title: '操作符',
      dataIndex: 'op',
      render: (text: string, record: TagRuleItem) => {
        return (
          <Select options={opOpts} value={text} onChange={(value) => onChangedRuleItem('op', value, record.index)} />
        );
      },
    },
    {
      title: '期待值',
      dataIndex: 'expected',
      render: (text: string, record: TagRuleItem) => {
        return <Input value={text} onChange={(e) => onChangedRuleItem('expected', e.target.value, record.index)} />;
      },
    },
    {
      title: '操作',
      dataIndex: 'action',
      render: (text: any, record: TagRuleItem, index: number) => (
        <Space>
          <PlusCircleOutlined onClick={addRuleItem} />
          {index > 0 && <MinusCircleOutlined onClick={() => removeRuleItem(record.index)} />}
        </Space>
      ),
    },
  ];
  return (
    <Table
      sticky
      scroll={{ x: '100%' }}
      columns={columns}
      rowKey={(record: any) => record.trace_id}
      dataSource={ruleList}
      pagination={false}
    />
  );
}

export default forwardRef(RuleTable);

效果图:
在这里插入图片描述

<think>好的,用户需要关于使用React和Ant Design实现可编辑表格的示例或教程。首先,我应该回忆一下Ant Design的文档,特别是Editable Table部分。记得Ant Design提供了EditableProTable和传统的通过自定义render方法实现可编辑表格的方式。可能需要分步骤说明,比如创建数据源、定义可编辑单元格、处理保存操作等。 用户提供的引用内容中有CSS样式,可能涉及到如何自定义可编辑表格的样式,比如.editable-cell类。需要确保在回答中提到如何结合这些样式,可能需要解释每个CSS类的作用,比如输入框和文本的包装器,以及图标的悬停效果。 另外,用户可能希望看到代码示例,包括React组件结构和状态管理。应该使用函数式组件和Hooks,比如useState来管理数据源和编辑状态。还要提到如何通过Ant Design的Table组件中的render属性来实现单元格的编辑模式切换。 需要注意用户提到的引用[^1]中的样式,可能需要指导用户将这些样式添加到他们的目中,比如通过CSS模块或全局样式文件。同时,要强调关键点,如数据双向绑定、保存逻辑和UI反馈。 最后,生成的相关问题需要围绕常见问题,比如样式自定义、保存到后端、验证输入等,确保覆盖用户可能的后续疑问。</think>### 使用 React 和 Ant Design 实现可编辑表格的步骤 #### 1. 基础表格结构搭建 使用 Ant Design 的 `Table` 组件创建静态表格: ```javascript import { Table, Input, Button } from 'antd'; import React, { useState } from 'react'; const EditableTable = () => { const [dataSource, setDataSource] = useState([ { key: '1', name: '张三', age: 25 }, { key: '2', name: '李四', age: 30 } ]); const columns = [ { title: '姓名', dataIndex: 'name' }, { title: '年龄', dataIndex: 'age' }, { title: '操作', dataIndex: 'operations' } ]; return <Table dataSource={dataSource} columns={columns} />; }; ``` #### 2. 实现单元格编辑功能 通过自定义 `render` 函数实现可编辑单元格: ```javascript const EditableCell = ({ editing, dataIndex, children, save, record, ...restProps }) => { const [value, setValue] = useState(record[dataIndex]); const saveHandler = () => { save({ ...record, [dataIndex]: value }); }; return ( <td {...restProps}> {editing ? ( <Input value={value} onChange={(e) => setValue(e.target.value)} onPressEnter={saveHandler} onBlur={saveHandler} /> ) : ( children )} </td> ); }; ``` #### 3. 添加编辑状态管理 使用 `useState` 管理编辑状态: ```javascript const [editingKey, setEditingKey] = useState(''); const isEditing = (record) => record.key === editingKey; const edit = (record) => { setEditingKey(record.key); }; const save = (newRecord) => { setDataSource(dataSource.map(item => item.key === newRecord.key ? newRecord : item )); setEditingKey(''); }; ``` #### 4. 完整组件集成 ```javascript const columns = [ { title: '姓名', dataIndex: 'name', render: (text, record) => ( <EditableCell editing={isEditing(record)} dataIndex="name" record={record} save={save} > {text} </EditableCell> ) }, // 类似实现年龄列... { title: '操作', render: (_, record) => ( isEditing(record) ? null : ( <Button onClick={() => edit(record)}>编辑</Button> ) ) } ]; ``` #### 5. 添加引用中的 CSS 样式 在样式文件中添加用户提供的样式规则[^1]: ```css /* editable-table.css */ .editable-cell { position: relative; } .editable-cell-input-wrapper, .editable-cell-text-wrapper { padding-right: 24px; } .editable-cell-icon { position: absolute; right: 0; cursor: pointer; } ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值