ant design 嵌套table表单
嵌套表单的封装
示例图跟下面的代码有不同,代码实现的是类似的逻辑。
封装的table表单TableForm.js
import React, { PureComponent, Fragment } from 'react'; import { Table, Button, Input, message, Popconfirm, Divider, Select } from 'antd'; import isEqual from 'lodash/isEqual'; const { Option } = Select; class TableForm extends PureComponent { index = 0; cacheOriginData = {}; constructor(props) { super(props); this.state = { data: props.value, loading: false, value: props.value, }; } static getDerivedStateFromProps(nextProps, preState) { if (isEqual(nextProps.value, preState.value)) { return null; } return { data: nextProps.value, value: nextProps.value, }; } getRowByKey(key, newData) { const { data } = this.state; return (newData || data).filter(item => item.key === key)[0]; } toggleEditable = (e, key) => { e.preventDefault(); const { data } = this.state; const newData = data.map(item => ({ ...item })); const target = this.getRowByKey(key, newData); if (target) { // 进入编辑状态时保存原始数据 if (!target.editable) { this.cacheOriginData[key] = { ...target }; } target.editable = !target.editable; this.setState({ data: newData }); } }; newMember = () => { const { data } = this.state; const newData = data.map(item => ({ ...item })); newData.push({ key: `ID_${new Date().getTime()}`, name: '', sub_name: '', reg: '', editable: true, isNew: true, }); this.index += 1; this.setState({ data: newData }); }; remove(key) { const { data } = this.state; const { onChange } = this.props; const newData = data.filter(item => item.key !== key); this.setState({ data: newData }); onChange(newData); } handleKeyPress(e, key) { if (e.key === 'Enter') { this.saveRow(e, key); } } handleFieldChange(e, fieldName, key) { const { data } = this.state; const newData = data.map(item => ({ ...item })); const target = this.getRowByKey(key, newData); if (target) { target[fieldName] = e.target?e.target.value:e; this.setState({ data: newData }); } } saveRow(e, key) { e.persist(); this.setState({ loading: true, }); setTimeout(() => { if (this.clickedCancel) { this.clickedCancel = false; return; } const target = this.getRowByKey(key) || {}; if (!target.sub_name || !target.name || !target.reg) { message.error('请填写完整信息。'); e.target.focus(); this.setState({ loading: false, }); return; } delete target.isNew; this.toggleEditable(e, key); const { data } = this.state; const { onChange } = this.props; onChange(data); this.setState({ loading: false, }); }, 500); } cancel(e, key) { this.clickedCancel = true; e.preventDefault(); const { data } = this.state; const newData = data.map(item => ({ ...item })); const target = this.getRowByKey(key, newData); if (this.cacheOriginData[key]) { Object.assign(target, this.cacheOriginData[key]); delete this.cacheOriginData[key]; } target.editable = false; this.setState({ data: newData }); this.clickedCancel = false; } render() { const columns = [ { title: '字段名', dataIndex: 'name', key: 'name', render: (text, record) => { if (record.editable) { return ( <Input value={text} autoFocus onChange={e => this.handleFieldChange(e, 'name', record.key)} onKeyPress={e => this.handleKeyPress(e, record.key)} /> ); } return text; }, }, { title: '资产类型', dataIndex: 'sub_name', key: 'sub_name', render: (text, record) => { if (record.editable) { return ( <Select defaultValue={text} onChange={e => this.handleFieldChange(e, 'sub_name', record.key)} > <Option value="1">是</Option> <Option value="0">否</Option> </Select> ); } return text; }, }, { title: ' ', dataIndex: 'reg', key: 'reg', render: (text, record) => { if (record.editable) { return ( <Input value={text} onChange={e => this.handleFieldChange(e, 'reg', record.key)} onKeyPress={e => this.handleKeyPress(e, record.key)} /> ); } return text; }, }, { title: '操作', key: 'action', width: 108, render: (text, record) => { const { loading } = this.state; if (!!record.editable && loading) { return null; } if (record.editable) { if (record.isNew) { return ( <span> <a onClick={e => this.saveRow(e, record.key)}>保存</a> <Divider type="vertical" /> <Popconfirm title="是否要删除此行?" onConfirm={() => this.remove(record.key)}> <a>删除</a> </Popconfirm> </span> ); } return ( <span> <a onClick={e => this.saveRow(e, record.key)}>保存</a> <Divider type="vertical" /> <a onClick={e => this.cancel(e, record.key)}>取消</a> </span> ); } return ( <span> <a onClick={e => this.toggleEditable(e, record.key)}>编辑</a> <Divider type="vertical" /> <Popconfirm title="是否要删除此行?" onConfirm={() => this.remove(record.key)}> <a>删除</a> </Popconfirm> </span> ); }, }, ]; const { loading, data } = this.state; return ( <Fragment> <Table loading={loading} columns={columns} dataSource={data} pagination={false} rowKey="key" size='small' // rowClassName={record => (record.editable ? styles.editable : '')} /> <Button style={{ width: '100%', marginTop: 16, marginBottom: 8 }} type="dashed" onClick={this.newMember} icon="plus" > 添加 </Button> </Fragment> ); } } export default TableForm;
table表单的使用
import TableForm from './tableForm'; tableChange = val => { console.log("e3e",val); this.setState({ tableVal: val }); // ref={(c)=>{this.searchForm=c}} form上添加这句,下面方便直接赋值给外层的表单 // this.searchForm.setFieldsValue({"assetTwo":vale}) }; const tableData = []; // 使用部分 <FormItem> {getFieldDecorator('assetTwo')( <div style={{ border: '1px solid #ccc' }}> <TableForm value={tableData} onChange={this.tableChange} // onChange={(val) => setFieldsValue({[`assetTwo`]: val, })} /> </div> )} </FormItem>