使用react+antd table的可编辑表格,当单元格的数据为空时,无法通过点击单元格进行修改数据。
如以下箭头所示,无法单击单元格增加数据。其余单元格,不为空的情况,是可以单击修改数据的。
前端代码如下:
const EditableContext = React.createContext(null);
const EditableRow = ({ index, ...props }) => {
const [form] = Form.useForm();
return (
<Form form={form} component={false}>
<EditableContext.Provider value={form}>
<tr {...props} />
</EditableContext.Provider>
</Form>
);
};
const EditableCell = ({
title,
editable,
children,
dataIndex,
record,
handleSave,
...restProps
}) => {
const [editing, setEditing] = useState(false);
const inputRef = useRef(null);
const form = useContext(EditableContext);
useEffect(() => {
if (editing) {
inputRef.current.focus();
}
}, [editing]);
const toggleEdit = () => {
console.log("toggleEdit:", editing)
setEditing(!editing);
form.setFieldsValue({
[dataIndex]: record[dataIndex],
});
};
const save = async () => {
try {
const values = await form.validateFields();
toggleEdit();
handleSave({
...record,
...values,
});
} catch (errInfo) {
console.log('Save failed:', errInfo);
}
};
let childNode = children;
if (editable) {
childNode = editing ? (
<Form.Item
style={{
margin: 0,
}}
name={dataIndex}
rules={[
{
required: false,
message: `${title} is required.`,
},
]}
>
<Input ref={inputRef} onPressEnter={save} onBlur={save} />
</Form.Item>
) : (
<div
className="editable-cell-value-wrap"
style={{
paddingRight: 24,
}}
onClick={toggleEdit}
>
{children}
</div>
);
}
return <td {...restProps}>{childNode}</td>;
};
const Test = React.forwardRef((props, ref) => {
const res = useContext(CountContext)
let data = JSON.parse(JSON.stringify(res.config.test_config))
const [dataSource, setDataSource] = useState(data);
const [count, setCount] = useState(dataSource.length);
useEffect(() => {
setDataSource(res.config.test_config);
setCount(dataSource.length);
}, [res.config.test_config])
const [loadings, setLoadings] = useState([]);
const handleDelete = (key) => {
const newData = dataSource.filter((item) => item.key !== key);
setDataSource(newData);
};
function translate_data() {}
useImperativeHandle(ref, () => {
return {
getData: () => { let result = translate_data(); return result },
}
}, [dataSource]);
const memoizedInputValue = useMemo(() => dataSource, [dataSource]);
const defaultColumns = [
{
title: 'hosts',
dataIndex: 'hosts',
width: '35%',
editable: true,
render: (text, record) => {},
},
{
title: 'level',
dataIndex: 'level',
width: '5%',
editable: true,
},
{
title: 'user',
dataIndex: 'user',
width: '5%',
editable: true,
},
{
title: 'passwd',
dataIndex: 'passwd',
width: '10%',
editable: true,
},
{
title: 'operation',
dataIndex: 'operation',
width: '5%',
render: (_, record) =>
dataSource.length >= 1 ? (
<Popconfirm title="Sure to delete?" onConfirm={() => handleDelete(record.key)}>
<a>Delete</a>
</Popconfirm>
) : null,
},
];
const handleAdd = () => {
const newData = {
key: count,
hosts: `192.168.10.11`,
user: 'network',
passwd: 'passwd',
};
setDataSource([...dataSource, newData]);
setCount(count + 1);
};
const hideLoadings = ((index) => {});
const handleExecute = () => {}
const enterLoading = (index) => {};
const handleSave = (row) => {
const newData = [...dataSource];
const index = newData.findIndex((item) => row.key === item.key);
const item = newData[index];
console.log("row:", JSON.stringify(row, null, '\t'))
newData.splice(index, 1, {
...item,
...row,
});
console.log("after new:", JSON.stringify(newData, null, '\t'))
setDataSource(newData);
};
const components = {
body: {
row: EditableRow,
cell: EditableCell,
},
};
const columns = defaultColumns.map((col) => {
if (!col.editable) {
return col;
}
return {
...col,
onCell: (record) => ({
record,
editable: col.editable,
dataIndex: col.dataIndex,
title: col.title,
handleSave,
}),
};
});
return (
// <Row className="comm-main" type="flex" justify="center">
// <Col className="comm-left" xs={16} sm={32} md={64} lg={32} xl={64} >
<div>
<Space/>
<Button
onClick={handleAdd}
type="primary"
style={{
marginBottom: 16,
}}
>
Add a row
</Button>
<Button
loading={loadings[1]}
onClick={() => enterLoading(1)}
type="primary"
style={{
marginBottom: 16,
}}
>
执行操作
</Button>
<Table
components={components}
rowClassName={() => 'editable-row'}
bordered
size={'middle'}
dataSource={dataSource}
columns={columns}
/>
</div>
// </Col>
// </Row>
);
});
export default Test;
当单元格数据为空时,无法通过点击单元格进行修改数据的原因是:空白单元格内没有可点击的内容,因此点击事件无法触发。解决方案是在空白单元格中添加一个非空白的占位符,如一个空格字符或者一个透明字符。
你可以通过修改EditableCell组件中的childNode的渲染逻辑来实现这一点。在childNode的渲染逻辑中,使用children作为判断条件。如果children为空,则使用一个空格字符作为占位符。这样,当单元格为空时,也可以触发点击事件了。
下面是修改后的EditableCell组件的部分代码:
现在,无论单元格是否为空,都可以通过点击进行修改数据了。