react + antd table可编辑单元格( 纯状态组件 )

4 篇文章 0 订阅
1 篇文章 0 订阅

Antd + React 可编辑单元格实现

小知识点 React.createContext()
父组件可以直接传值到子组件、或者孙子组件,无需通过props进行传值,以前方便、简洁。包含Provider、Consumer组件,Provider的value属性就是所有子孙组件通用的都可以获取到的,而想使用这个value子孙组件必须被Consumer组件包裹

正题

可编辑单元格的实现总体分为三部分

注意:如果需要使用状态组件,那么下面的代码会很适合你来使用,如果你要使用非状态组件,建议直接去antd( antd4+ )官网( https://ant-design.gitee.io/components/table-cn/#components-table-demo-edit-cell )看( 官网采用react的hooks,如果不了解的话可以去 https://react.html.cn/docs/hooks-overview.html 了解)


一、EditableRow ( 名字随意 )

class EditableRow extends Component {
  returnForm = React.createRef();
  render() {
    return (
      <Form ref={this.returnForm} component={false}>
        //父组件
        <EditableContext.Provider value={this.returnForm}>
          <tr {...this.props} />
        </EditableContext.Provider>
      </Form>
    );
  }
}

二、EditableCell ( 名字随意 )

class EditableCell extends Component {
  state = {
    editing: false
  };

  toggleEdit = () => {
    const editing = !this.state.editing;
    this.setState({ editing }, () => {
      if (editing) {
        this.input.focus();
      }
    });
  };

  save = (e) => {
    const { record, handleSave } = this.props;
    let values = this.form.current.getFieldsValue();
    this.toggleEdit();
    handleSave({ ...record, ...values });
  };

  renderCell = (form) => {
    this.form = form;
    const { children, dataIndex, record, title } = this.props;
    const { editing } = this.state;
    let formParams = {
      one: {
        name: dataIndex,
        rules: [
          {
            required: true,
            message: `${title} is required.`
          }
        ],
        initialValue: record[dataIndex]
      }
    };
    return editing ? (
      <Form.Item {...formParams.one} style={{ margin: 0 }}>
        <Input
          ref={(node) => (this.input = node)}
          onPressEnter={this.save}
          onBlur={this.save}
        />
      </Form.Item>
    ) : (
      <div
        className="editable-cell-value-wrap"
        style={{ paddingRight: 24 }}
        onClick={this.toggleEdit}
      >
        {children}
      </div>
    );
  };

  render() {
    const {
      editable,
      dataIndex,
      title,
      record,
      index,
      handleSave,
      children,
      ...restProps
    } = this.props;
    return (
      <td {...restProps}>
        {editable ? (
          <EditableContext.Consumer>{this.renderCell}</EditableContext.Consumer>//子孙组件
        ) : (
          children
        )}
      </td>
    );
  }
}

**三、EditableTable ( 名字随意 ) **

class EditableTable extends Component {
  constructor(props) {
    super(props);
    this.columns = [
      {
        title: "name",
        dataIndex: "name",
        width: "30%",
        editable: true
      },
      {
        title: "age",
        dataIndex: "age"
      },
      {
        title: "address",
        dataIndex: "address"
      },
      {
        title: "operation",
        dataIndex: "operation",
        render: (_, record) =>
          this.state.dataSource.length >= 1 ? (
            <Popconfirm
              title="Sure to delete?"
              onConfirm={() => this.handleDelete(record.key)}
            >
              <a>Delete</a>
            </Popconfirm>
          ) : null
      }
    ];
    this.state = {
      dataSource: [
        {
          key: "0",
          name: "Edward King 0",
          age: "32",
          address: "London, Park Lane no. 0"
        },
        {
          key: "1",
          name: "Edward King 1",
          age: "32",
          address: "London, Park Lane no. 1"
        }
      ],
      count: 2
    };
  }

  handleDelete = (key) => {
    const dataSource = [...this.state.dataSource];
    this.setState({
      dataSource: dataSource.filter((item) => item.key !== key)
    });
  };
  handleAdd = () => {
    const { count, dataSource } = this.state;
    const newData = {
      key: count,
      name: `Edward King ${count}`,
      age: "32",
      address: `London, Park Lane no. ${count}`
    };
    this.setState({
      dataSource: [...dataSource, newData],
      count: count + 1
    });
  };
  handleSave = (row) => {
    const newData = [...this.state.dataSource];
    const index = newData.findIndex((item) => row.key === item.key);
    const item = newData[index];
    newData.splice(index, 1, { ...item, ...row });
    this.setState({
      dataSource: newData
    });
  };

  render() {
    const { dataSource } = this.state;
    const components = {
      body: {
        row: EditableRow,
        cell: EditableCell
      }
    };
    const columns = this.columns.map((col) => {
      if (!col.editable) {
        return col;
      }

      return {
        ...col,
        onCell: (record) => ({
          record,
          editable: col.editable,
          dataIndex: col.dataIndex,
          title: col.title,
          handleSave: this.handleSave
        })
      };
    });
    return (
      <div>
        <Button
          onClick={this.handleAdd}
          type="primary"
          style={{
            marginBottom: 16
          }}
        >
          Add a row
        </Button>
        <Table
          components={components}
          rowClassName={() => "editable-row"}
          bordered
          dataSource={dataSource}
          columns={columns}
        />
      </div>
    );
  }
}

整体代码

//发送请求重新获取更改后的数据
import React,{Component} from "react";
import ReactDOM from "react-dom";
import "antd/dist/antd.css";
import "./index.css";
import { Table, Input, Button, Popconfirm, Form } from "antd";

const EditableContext = React.createContext(null); 

class EditableRow extends Component {
  returnForm = React.createRef();
  render() {
    return (
      <Form ref={this.returnForm} component={false}>
        <EditableContext.Provider value={this.returnForm}>
          <tr {...this.props} />
        </EditableContext.Provider>
      </Form>
    );
  }
}

class EditableCell extends Component {
  state = {
    editing: false
  };

  toggleEdit = () => {
    const editing = !this.state.editing;
    this.setState({ editing }, () => {
      if (editing) {
        this.input.focus();
      }
    });
  };

  save = (e) => {
    const { record, handleSave } = this.props;
    let values = this.form.current.getFieldsValue();
    this.toggleEdit();
    handleSave({ ...record, ...values });
  };

  renderCell = (form) => {
    this.form = form;
    const { children, dataIndex, record, title } = this.props;
    const { editing } = this.state;
    let formParams = {
      one: {
        name: dataIndex,
        rules: [
          {
            required: true,
            message: `${title} is required.`
          }
        ],
        initialValue: record[dataIndex]
      }
    };
    return editing ? (
      <Form.Item {...formParams.one} style={{ margin: 0 }}>
        <Input
          ref={(node) => (this.input = node)}
          onPressEnter={this.save}
          onBlur={this.save}
        />
      </Form.Item>
    ) : (
      <div
        className="editable-cell-value-wrap"
        style={{ paddingRight: 24 }}
        onClick={this.toggleEdit}
      >
        {children}
      </div>
    );
  };

  render() {
    const {
      editable,
      dataIndex,
      title,
      record,
      index,
      handleSave,
      children,
      ...restProps
    } = this.props;
    return (
      <td {...restProps}>
        {editable ? (
          <EditableContext.Consumer>{this.renderCell}</EditableContext.Consumer>
        ) : (
          children
        )}
      </td>
    );
  }
}

class EditableTable extends Component {
  constructor(props) {
    super(props);
    this.columns = [
      {
        title: "name",
        dataIndex: "name",
        width: "30%",
        editable: true
      },
      {
        title: "age",
        dataIndex: "age"
      },
      {
        title: "address",
        dataIndex: "address"
      },
      {
        title: "operation",
        dataIndex: "operation",
        render: (_, record) =>
          this.state.dataSource.length >= 1 ? (
            <Popconfirm
              title="Sure to delete?"
              onConfirm={() => this.handleDelete(record.key)}
            >
              <a>Delete</a>
            </Popconfirm>
          ) : null
      }
    ];
    this.state = {
      dataSource: [
        {
          key: "0",
          name: "Edward King 0",
          age: "32",
          address: "London, Park Lane no. 0"
        },
        {
          key: "1",
          name: "Edward King 1",
          age: "32",
          address: "London, Park Lane no. 1"
        }
      ],
      count: 2
    };
  }

  handleDelete = (key) => {
    const dataSource = [...this.state.dataSource];
    this.setState({
      dataSource: dataSource.filter((item) => item.key !== key)
    });
  };
  handleAdd = () => {
    const { count, dataSource } = this.state;
    const newData = {
      key: count,
      name: `Edward King ${count}`,
      age: "32",
      address: `London, Park Lane no. ${count}`
    };
    this.setState({
      dataSource: [...dataSource, newData],
      count: count + 1
    });
  };
  handleSave = (row) => {
    const newData = [...this.state.dataSource];
    const index = newData.findIndex((item) => row.key === item.key);
    const item = newData[index];
    newData.splice(index, 1, { ...item, ...row });
    this.setState({
      dataSource: newData
    });
  };

  render() {
    const { dataSource } = this.state;
    const components = {
      body: {
        row: EditableRow,
        cell: EditableCell
      }
    };
    const columns = this.columns.map((col) => {
      if (!col.editable) {
        return col;
      }

      return {
        ...col,
        onCell: (record) => ({
          record,
          editable: col.editable,
          dataIndex: col.dataIndex,
          title: col.title,
          handleSave: this.handleSave
        })
      };
    });
    return (
      <div>
        <Button
          onClick={this.handleAdd}
          type="primary"
          style={{
            marginBottom: 16
          }}
        >
          Add a row
        </Button>
        <Table
          components={components}
          rowClassName={() => "editable-row"}
          bordered
          dataSource={dataSource}
          columns={columns}
        />
      </div>
    );
  }
}

ReactDOM.render(<EditableTable />, document.getElementById("container"));

  • 0
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
以下是一个简单的可编辑表格的示例代码,使用React Hook和Antd组件库: ```javascript import React, { useState } from 'react'; import { Table, Input, InputNumber, Popconfirm, Form } from 'antd'; const EditableCell = ({ editing, dataIndex, title, inputType, record, index, children, ...restProps }) => { const inputNode = inputType === 'number' ? <InputNumber /> : <Input />; return ( <td {...restProps}> {editing ? ( <Form.Item name={dataIndex} style={{ margin: 0 }} rules={[ { required: true, message: `Please Input ${title}!`, }, ]} > {inputNode} </Form.Item> ) : ( children )} </td> ); }; const EditableTable = () => { const [form] = Form.useForm(); const [data, setData] = useState([ { key: '1', name: 'John Brown', age: 32, address: 'New York No. 1 Lake Park', }, { key: '2', name: 'Joe Black', age: 42, address: 'London No. 1 Lake Park', }, { key: '3', name: 'Jim Green', age: 32, address: 'Sidney No. 1 Lake Park', }, { key: '4', name: 'Jim Red', age: 32, address: 'London No. 2 Lake Park', }, ]); const [editingKey, setEditingKey] = useState(''); const isEditing = (record) => record.key === editingKey; const edit = (record) => { form.setFieldsValue({ name: '', age: '', address: '', ...record, }); setEditingKey(record.key); }; const cancel = () => { setEditingKey(''); }; const save = async (key) => { try { const row = await form.validateFields(); const newData = [...data]; const index = newData.findIndex((item) => key === item.key); if (index > -1) { const item = newData[index]; newData.splice(index, 1, { ...item, ...row }); setData(newData); setEditingKey(''); } else { newData.push(row); setData(newData); setEditingKey(''); } } catch (errInfo) { console.log('Validate Failed:', errInfo); } }; const columns = [ { title: 'Name', dataIndex: 'name', width: '25%', editable: true, }, { title: 'Age', dataIndex: 'age', width: '15%', editable: true, }, { title: 'Address', dataIndex: 'address', width: '40%', editable: true, }, { title: 'Action', dataIndex: 'action', render: (_, record) => { const editable = isEditing(record); return editable ? ( <span> <a href="javascript:;" onClick={() => save(record.key)} style={{ marginRight: 8 }} > Save </a> <Popconfirm title="Sure to cancel?" onConfirm={cancel}> <a>Cancel</a> </Popconfirm> </span> ) : ( <a disabled={editingKey !== ''} onClick={() => edit(record)}> Edit </a> ); }, }, ]; const mergedColumns = columns.map((col) => { if (!col.editable) { return col; } return { ...col, onCell: (record) => ({ record, inputType: col.dataIndex === 'age' ? 'number' : 'text', dataIndex: col.dataIndex, title: col.title, editing: isEditing(record), }), }; }); return ( <Form form={form} component={false}> <Table components={{ body: { cell: EditableCell, }, }} bordered dataSource={data} columns={mergedColumns} rowClassName="editable-row" pagination={{ onChange: cancel, }} /> </Form> ); }; export default EditableTable; ``` 这个表格组件的主要思路是: 1. 使用`useState` Hook来保存表格数据和当前正在编辑的行的key。 2. 创建一个可编辑单元格组件`EditableCell`,根据`editing`属性来展示编辑状态或者展示状态。当编辑状态时,渲染一个`antd`的`Form.Item`,提供一个可编辑的输入框。 3. 创建一个可编辑的表格组件`EditableTable`,渲染一个`antd`的`Table`组件。 4. 在表格的每一列中添加一个`editable`属性,表示该列是否可编辑。对于可编辑的列,使用`onCell`属性指定可编辑单元格的属性。 5. 在渲染表格的每一行时,根据当前行是否处于编辑状态来决定展示编辑状态还是展示状态。如果处于编辑状态,则渲染可编辑单元格,否则渲染非可编辑单元格。 6. 在表格中添加编辑和保存按钮,点击编辑按钮时进入编辑状态,点击保存按钮时保存修改。同时,保存和取消操作会将当前行的编辑状态取消。 这样,我们就完成了一个简单的可编辑表格。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值