目标

  • 添加行:点击添加行,当有行在编辑并未进行保存时提示先保存;表格行中未有未保存的内容时,表格最后加一行,并可以输入内容,当点击取消时,整行删除不保存。
  • 删除行:所在行删除
  • 保存行:保存所在行

详细代码

index.js

import React from 'react';
import EditableFormTable from './EditableFormTable';

export default class HelloAdmin extends React.Component {
    constructor(props) {
        super(props);
        this.state = {};
    }

    componentDidMount() {}

    render() {
        return <EditableFormTable />;
    }
}

TableData.js

const data = [];
for (let i = 0; i < 6; i += 1) {
    data.push({
        key: i.toString(),
        name: `Edrward ${i}`,
        age: 32,
        address: `London Park no. ${i}`,
    });
}
export const Tabledata = data;

TableContext.js

import React from 'react';

export const EditableContext = React.createContext();

EditableFormTable.js

import React from 'react';
import { Popconfirm, Form, Table, Button, message } from 'antd';
import PropTypes from 'prop-types';
import { Tabledata } from './TableData';
import { EditableContext } from './TableContext';
import EditableCell from './EditableCell';

class EditableTable extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            data: Tabledata,
            editingKey: '',
        };
        this.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: 'operation',
                dataIndex: 'operation',
                render: (text, record) => {
                    const { editingKey } = this.state;
                    const editable = this.isEditing(record);
                    return editable ? (
                        <span>
                            <EditableContext.Consumer>
                                {(form) => (
                                    <button
                                        onClick={() => this.save(form, record.key)}
                                        style={{ marginRight: 8 }}
                                        type="button"
                                    >
                                        Save
                                    </button>
                                )}
                            </EditableContext.Consumer>
                            <Popconfirm
                                title="Sure to cancel?"
                                onConfirm={() => this.cancel(record.key)}
                            >
                                <button style={{ marginRight: 8 }} type="button">
                                    Cancel
                                </button>
                            </Popconfirm>
                            <Popconfirm
                                title="Sure to delete?"
                                onConfirm={() => this.delete(record.key)}
                            >
                                <button type="button">delete</button>
                            </Popconfirm>
                        </span>
                    ) : (
                        <button
                            type="button"
                            disabled={editingKey !== ''}
                            onClick={() => this.edit(record.key)}
                        >
                            Edit
                        </button>
                    );
                },
            },
        ];
    }

    isEditing = (record) => {
        const { editingKey } = this.state;
        return record.key === editingKey;
    };

    cancel = (key) => {
        if (key.length > 6) {
            const { data } = this.state;
            const newData = data;
            newData.splice(data.length - 1, 1);
            this.setState({ data: newData, editingKey: key });
        }
        this.setState({ editingKey: '' });
    };

    delete = (key) => {
        const { data } = this.state;
        const newData = data;
        const index = newData.findIndex((item) => key === item.key);
        newData.splice(index, 1);
        this.setState({ data: newData, editingKey: '' });
    };

    save(form, key) {
        form.validateFields((error, row) => {
            if (error) {
                return;
            }
            const { data } = this.state;
            const newData = [...data];
            const index = newData.findIndex((item) => key === item.key);
            if (index > -1) {
                const item = newData[index];
                newData.splice(index, 1, {
                    ...item,
                    ...row,
                });
                this.setState({ data: newData, editingKey: '' });
            } else {
                newData.push(row);
                this.setState({ data: newData, editingKey: '' });
            }
        });
    }

    edit = (key) => {
        this.setState({ editingKey: key });
    };

    handleAdd = () => {
        const { data, editingKey } = this.state;
        if (editingKey !== '') {
            message.error('请先保存');
            return;
        }
        const key = new Date().toString();
        const row = {
            key,
            name: '',
            age: '',
            address: '',
        };
        console.log(data);
        console.log(row);
        const newData = data;
        newData.splice(data.length, 1, row);
        this.setState({ data: newData, editingKey: key });
        console.log(newData);
    };

    render() {
        const components = {
            body: {
                cell: EditableCell,
            },
        };
        const columns = this.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: this.isEditing(record),
                }),
            };
        });
        const { data } = this.state;
        const { form } = this.props;
        return (
            <EditableContext.Provider value={form}>
                <Button onClick={this.handleAdd} type="primary" style={{ marginBottom: 16 }}>
                    Add a row
                </Button>
                <Table
                    components={components}
                    bordered
                    dataSource={data}
                    columns={columns}
                    rowClassName="editable-row"
                    pagination={{
                        onChange: this.cancel,
                    }}
                />
            </EditableContext.Provider>
        );
    }
}

const EditableFormTable = Form.create()(EditableTable);
export default EditableFormTable;

EditableTable.propTypes = {
    form: PropTypes.object,
};

EditableCell.js

import React from 'react';
import { Input, InputNumber, Form } from 'antd';
import { EditableContext } from './TableContext';

const FormItem = Form.Item;

class EditableCell extends React.Component {
    getInput = () => {
        const { inputType } = this.props;
        if (inputType === 'number') {
            return <InputNumber />;
        }
        return <Input />;
    };

    renderCell = ({ getFieldDecorator }) => {
        const {
            editing,
            dataIndex,
            title,
            inputType,
            record,
            index,
            children,
            ...restProps
        } = this.props;
        return (
            <td {...restProps}>
                {editing ? (
                    <FormItem style={{ margin: 0 }}>
                        {getFieldDecorator(dataIndex, {
                            rules: [
                                {
                                    required: true,
                                    message: `Please Input ${title}!`,
                                },
                            ],
                            initialValue: record[dataIndex],
                        })(this.getInput())}
                    </FormItem>
                ) : (
                    children
                )}
            </td>
        );
    };

    render() {
        return <EditableContext.Consumer>{this.renderCell}</EditableContext.Consumer>;
    }
}

export default EditableCell;
06-14 03:53