antd3官网的表单介绍中,自定义的表单组件必须要传一个value跟onChange方法,才能和表单联动数据
官网的自定义表单控件:3x.ant.design/components/…
- 要注意的是,官网的写法有两种,示例写法是class类组件的写法,函数组件有些不同,需要加ref。其实这个很简单,只需要看一眼别人怎么写的就能写出来,我这里是函数组件的写法,复用性不高,就是记录一下。
import { Table, Input, Button, Alert } from 'antd';
import React, { useState } from 'react';
import styles from './index.scss';
let editFlag = false;
function EditableTable({ value = {}, onChange }, ref) {
const [state, setState] = useState(() => {
let arr = [];
if (value && Object.keys(value).length !== 0) {
let count = 0;
for (const k in value) {
arr.push({
key: k,
value: value[k],
valueEdit: false,
keyEdit: false,
id: count
});
count++;
}
return arr;
}
return arr;
});
const [warningVisible, setWarningVisible] = useState(false);
const columns = [
{
title: 'Key',
dataIndex: 'key',
align: 'center',
ellipsis: true,
render: (text, record, index) => {
// console.log(record, index);
return (
<div style={{ width: '100%', height: '100%' }}>
{record.keyEdit ? (
<Input
autoFocus
style={{ width: '100%' }}
value={text}
onChange={(e) => {
const v = e.target.value;
v.trim() === ''
? setWarningVisible(true)
: setWarningVisible(false);
handleChange(v, index, 'key');
}}
onPressEnter={(e) =>
handleOver(e, index, record.keyEdit, 'key')
}
onBlur={(e) => handleOver(e, index, record.keyEdit, 'key')}
></Input>
) : (
<div
style={{ width: '100%', height: '100%' }}
onClick={() => {
if (editFlag) {
return;
}
editFlag = true;
toggleEdit(index, record.keyEdit, 'key');
}}
>
{text}
</div>
)}
</div>
);
}
},
{
title: 'Value',
dataIndex: 'value',
align: 'center',
ellipsis: true,
render: (text, record, index) => {
// console.log(record, index);
return (
<div style={{ width: '100%', height: '100%' }}>
{record.valueEdit ? (
<Input
autoFocus
style={{ width: '100%' }}
value={text}
onChange={(e) => {
const v = e.target.value;
v.trim() === ''
? setWarningVisible(true)
: setWarningVisible(false);
handleChange(v, index, 'value');
}}
onPressEnter={(e) =>
handleOver(e, index, record.valueEdit, 'value')
}
onBlur={(e) => handleOver(e, index, record.valueEdit, 'value')}
></Input>
) : (
<div
style={{ width: '100%', height: '100%' }}
onClick={() => {
if (editFlag) {
return;
}
editFlag = true;
toggleEdit(index, record.valueEdit, 'value');
}}
>
{text}
</div>
)}
</div>
);
}
},
{
title: '操作',
align: 'center',
render: (text, record, index) => (
<Button type="link" onClick={() => handleDelete(index)}>
删除
</Button>
)
}
];
// 增
const handleAdd = () => {
setState([
...state,
{
key: 'initialKey',
value: 'initialValue',
valueEdit: false,
keyEdit: true
}
]);
};
//删
const handleDelete = (index) => {
setState(state.filter((item, i) => i !== index));
triggerChange();
};
// 切换编辑状态
const toggleEdit = (i, editing, type) => {
// console.log(i, editing);
type === 'value'
? setState(
state.map((item, index) =>
index === i ? { ...item, valueEdit: !editing } : item
)
)
: setState(
state.map((item, index) =>
index === i ? { ...item, keyEdit: !editing } : item
)
);
};
// inputChange
const handleChange = (v, i, type) => {
type === 'value'
? setState(
state.map((item, index) =>
index === i ? { ...item, value: v } : item
)
)
: setState(
state.map((item, index) => (index === i ? { ...item, key: v } : item))
);
};
const handleOver = (e, index, editing, type) => {
const v = e.target.value;
if (v.trim() === '') {
e.target.focus();
return setWarningVisible(true);
}
setWarningVisible(false);
toggleEdit(index, editing, type);
triggerChange();
editFlag = false;
};
// changeIncomingValue
const triggerChange = () => {
let newValue = {};
state.forEach((item) => {
newValue[item.key] = item.value;
});
console.log(newValue);
onChange && onChange(newValue);
};
return (
<div ref={ref} className={styles.root}>
<Button
onClick={handleAdd}
type="primary"
style={{ margin: '0 16px 16px' }}
>
添加
</Button>
{warningVisible ? (
<Alert message="值不可以为空!" type="error" showIcon />
) : (
''
)}
<Table
pagination={false}
bordered={true}
dataSource={state}
columns={columns}
rowKey={(record, i) => i}
/>
</div>
);
}
export default React.forwardRef(EditableTable);
css:
.root {
:global {
.ant-alert {
display: inline-block;
width: auto;
font-size: 12px;
}
.ant-table-row {
td {
padding: 0 !important;
height: 50px;
line-height: 50px;
overflow: hidden;
}
}
}
}
使用:
<Form.Item>
{getFieldDecorator('authHeaders', {
initialValue:
state.dataAccessInfo?.content?.authInfo
?.headers || {}
})(<EditableTable></EditableTable>)}
</Form.Item>