首先是table有多个按钮可以从外界传入,使用的是tsx的children进行插槽 关键代码
interface EditableCellProps {
...
//插槽的ts类型校验
children?: React.ReactNode;
}
const EditableTable: React.FC<EditableTableProps> = ({
...
children
}) => {
<>
<span>
<Button type="primary" onClick={handleAdd} style={{ marginBottom: 16 }}>
<PlusOutlined /> Add Row
</Button>
{/* 遍历传入的插槽,判断是不是react的节点,不是就返回child,是就渲染节点 */}
{React.Children.map(children, (child, index) => {
if (React.isValidElement(child)) {
return React.cloneElement(child, {key: `slot-${index}`,style: { marginLeft: "10px" } // 可以为插槽添加样式
} as React.HTMLAttributes<HTMLElement> & { style: CSSProperties });
}
return child;
})}
</span>
}
父组件使用
<EditableTable>
<Button type="primary" onClick={() => handleTableChange({}, {}, {})} style={{ marginBottom: "10px", width: "100px" }}>刷新</Button>
</EditableTable>
antd的数据源是key作为唯一的key,如果数据是id,可以将ttable指定为这样<Table rowKey="id"/>
setDataSource([
//官方的代码的数据源是key:1,想改为id,如上设置即可
{ id: 1, name: "John Brown", age: 32, address: "New York No. 1 Lake Park" },
{ id: 2, name: "Jim Green", age: 42, address: "London No. 1 Lake Park" },
{ id: 3, name: "Joe Black", age: 32, address: "Sidney No. 1 Lake Park" }
]);
完整的代码
import React, { CSSProperties, useState, useEffect } from "react";
import { Table, Button, Modal, Form, Input } from "antd";
import { PlusOutlined } from "@ant-design/icons";
interface EditableTableProps {
columns: any[];
dataSource: any[];
loading: boolean;
total: number;
onChange: (pagination: any, filters: any, sorter: any) => void;
onDelete: (record: any) => void;
onAdd: (dataSource: any) => void;
children: React.ReactNode;
}
interface Info {
id?: number | string;
title?: string;
age?: number;
address?: string;
}
const EditableTable: React.FC<EditableTableProps> = ({
columns,
dataSource,
loading,
total,
onChange,
onDelete,
onAdd,
children
}) => {
const [form] = Form.useForm();
const [data, setData] = useState<any[]>(dataSource);
const [visible, setVisible] = useState(false);
// 判断是add还是edit
const [actionType, setActionType] = useState("");
// 将其他的信息临时存到info变量里面
const [info, setInfo] = useState<Info>({});
useEffect(() => {
//获取父组件传过来的data,关闭弹窗清空变量
setData(dataSource);
if (!visible) {
setInfo({});
}
}, [dataSource, visible]);
const edit = (record: any) => {
setVisible(true);
setInfo(record);
form.setFieldsValue({ ...record });
setActionType("edit");
};
const handleDelete = (record: any) => {
const newData = [...data];
const index = newData.findIndex(item => record.id === item.id);
console.log("newData", newData, record, index);
if (index > -1) {
newData.splice(index, 1);
setData(newData);
onDelete(record);
}
};
const handleAdd = () => {
console.log("form", form);
setVisible(true);
setActionType("add");
};
const handleOk = () => {
console.log("setData(dataSource);", form.getFieldsValue());
console.log("values", form);
form.submit();
};
const handleCancel = () => {
setVisible(false);
};
const handleFinish = (values: any, actionType: string) => {
const newData = [...data];
if (actionType === "add") {
newData.push({ id: (newData.length + 1) as number, ...values });
} else if (actionType === "edit") {
// 根据数据的 id 查找要编辑的数据,并更新它的值
const index = newData.findIndex(item => item.id === info.id);
if (index > -1) {
newData[index] = {
id: info.id,
...values
};
}
}
setData(newData);
onAdd(newData);
// 清空表单
form.resetFields();
setVisible(false);
};
const handleTableChange = (pagination: any, filters: any, sorter: any) => {
onChange(pagination, filters, sorter);
};
const columnsWithEditAndDelete = [
...columns,
{
title: "Action",
dataIndex: "action",
render: (_: any, record: any) => {
return (
<span>
<Button type="link" onClick={() => edit(record)} style={{ marginRight: 8 }}>
Edit
</Button>
<Button type="link" danger onClick={() => handleDelete(record)}>
Delete
</Button>
</span>
);
}
}
];
return (
<>
<span>
<Button type="primary" onClick={handleAdd} style={{ marginBottom: 16 }}>
<PlusOutlined /> Add Row
</Button>
{/* 遍历传入的插槽,判断是不是react的节点,不是就返回child,是就渲染节点 */}
{React.Children.map(children, (child, index) => {
if (React.isValidElement(child)) {
return React.cloneElement(child, {
id: `slot-${index}`,
style: { marginLeft: "10px" } // 可以为插槽添加样式
} as React.HTMLAttributes<HTMLElement> & { style: CSSProperties });
}
return child;
})}
</span>
<Table
columns={columnsWithEditAndDelete}
dataSource={data}
loading={loading}
pagination={{
total: total,
showSizeChanger: true,
showQuickJumper: true
}}
onChange={handleTableChange}
rowKey="id"
/>
{/* Warning: Instance created by useForm is not connected to any Form element. Forget to pass form prop? */}
{/* 页面初始化,调用 form 方法时,因为 Modal 还未初始化,导致 form 这时候还没有挂载的 element,这时候调用form的方法就会报错, 此时 form 没有关联任何 Form 组件。 */}
{/* 解决方法: getContainer={false} */}
<Modal visible={visible} getContainer={false} title="Add New Row" onCancel={handleCancel} onOk={handleOk} destroyOnClose>
<Form form={form} onFinish={values => handleFinish(values, actionType)}>
{columns.map(column => (
<Form.Item
key={column.dataIndex}
name={column.dataIndex}
label={column.title}
rules={[
{
required: true,
message: `Please enter ${column.title}!`
}
]}
>
{column.inputType === "number" ? <Input type="number" /> : <Input />}
</Form.Item>
))}
</Form>
</Modal>
</>
);
};
export default EditableTable;