我写了一个可编辑Cell的List:
import React, { useState } from 'react';
import type { TableProps } from 'antd';
import { Button, Form, Input, InputNumber, Popconfirm, Space, Table, Typography } from 'antd';
interface EditableCellProps extends React.HTMLAttributes<HTMLElement> {
editing: boolean;
dataIndex: string;
title: any;
inputType: 'number' | 'text';
record: any;
index: number;
}
const EditableCell: React.FC<React.PropsWithChildren<EditableCellProps>> = ({
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>
);
};
// 使用泛型 T 来表示数据类型
interface IndexProps<T> {
itemType: {
[K in keyof T]: string;
};
initialData: T[];
onEdit: (record: T) => void;
onDelete: (record: T) => void;
}
const Index = <T extends { key: React.Key }>({ itemType, initialData, onEdit, onDelete }: IndexProps<T>) => {
const [form] = Form.useForm();
const [data, setData] = useState(initialData);
const [editingKey, setEditingKey] = useState<React.Key>('');
const isEditing = (record: T) => record.key === editingKey;
const handleEdit = (record: T) => {
form.setFieldsValue({ ...record });
setEditingKey(record.key);
};
const handleCancel = () => {
setEditingKey('');
};
const handleSave = async (key: React.Key) => {
try {
const row = (await form.validateFields()) as T;
const newData = [...data];
const index = newData.findIndex((item) => key === item.key);
if (index > -1) {
const item = newData[index];
newData.splice(index, 1, {
...item,
...row,
});
onEdit(row);
setData(newData);
setEditingKey('');
} else {
newData.push(row);
onEdit(row);
setData(newData);
setEditingKey('');
}
} catch (errInfo) {
console.log('Validate Failed:', errInfo);
}
};
const handleDelete = (record: T) => {
onDelete(record);
};
const generateColumns = () => {
const columns = [];
for (const key in itemType) {
if (key === 'key') continue;
columns.push({
title: key,
dataIndex: key,
width: key === 'name' ? '25%' : '100px',
editable: true,
});
}
columns.push({
title: 'operation',
dataIndex: 'operation',
render: (_: any, record: T) => {
const editable = isEditing(record);
return editable ? (
<span>
<Typography.Link onClick={() => handleSave(record.key)} style={{ marginInlineEnd: 8 }}>
保存
</Typography.Link>
<Popconfirm title="确定要取消吗?" onConfirm={handleCancel}>
<a>取消</a>
</Popconfirm>
</span>
) : (
<>
<Space>
<Button
size='small'
variant="filled"
onClick={() => handleEdit(record)}
>
编辑
</Button>
<Popconfirm title="确定要删除吗?" onConfirm={() => handleDelete(record)}>
<Button
size='small'
color="danger"
variant="filled">
删除
</Button>
</Popconfirm>
</Space>
</>
);
},
});
return columns;
};
const columns = generateColumns();
const mergedColumns: TableProps<T>['columns'] = columns.map((col) => {
if (!col.editable) {
return col;
}
return {
...col,
onCell: (record: T) => ({
record,
inputType: col.dataIndex === 'age' ? 'number' : 'text',
dataIndex: col.dataIndex,
title: col.title,
editing: isEditing(record),
}),
};
});
return (
<Form form={form} component={false}>
<Table<T>
components={{
body: { cell: EditableCell },
}}
bordered
dataSource={data}
columns={mergedColumns}
rowClassName="editable-row"
pagination={false}
/>
</Form>
);
};
export default Index;
使用方式:
const funcEditListType = {
key: '',
funcname: '',
funpath: ''
};
const funcEditListInitialData: typeof funcEditListType[] = [
{
key: '1',
funcname: `Edward 1`,
funpath: '/path/to/1234567890--9876543456'
}
];
const handleFuncEdit = (record: typeof funcEditListType) => {
console.log('编辑操作回调,记录:', record);
};
const handleFuncDelete = (record: typeof funcEditListType) => {
console.log('删除操作回调,记录:', record);
};
...
<EditableList itemType={funcEditListType} initialData={funcEditListInitialData} onEdit={handleFuncEdit} onDelete={handleFuncDelete} />
现在的问题是,比如:内容过长会直接冲出父容器:
请问,是否可以设定Table的宽度,或者不让其超过父容器呢?
加scroll和width