react表单组件怎么写(react antd实现动态增减表单)
类别:编程学习 浏览量:841
时间:2022-01-27 01:48:52 react表单组件怎么写
react antd实现动态增减表单之前写动态表单遇到过坑,就是用index下标做key会导致bug,而且很严重!
今天有空写下文章记录下:怎么处理和逻辑
我用的是antd3的版本,3和4的表单有点不一样,不过差别应该不大。
需求:
1、选择类型切换展示固定的模板
2、通过新增字段可以动态增减表单里面的每一行
3、控制每一行的字段是否需要必填
4、编辑时候回填参数
效果图:
部分关键代码:
import React, { Component } from 'react'; import styles from './index.less'; import { Table, Button, Select, Popconfirm, Modal, Form, Input, Radio, Row, Col, Tooltip, Icon, message, Pagination, InputNumber, } from 'antd'; const Option = Select.Option; const FormItem = Form.Item; let id = 0; @Form.create() class Index extends Component { marketId = 0; state = { selectType: '', orderType: 1, //文章1 地图2 typeLoading: false, isEdit: false, lookVisible: false, visible: false, pageSize: 10, pageNum: 1, keyWord: '', row: {}, typeList: {}, mock: {}, mapType: [{ 'fieldName': 'name', 'isImg': 0, 'order': 0, 'remarks': '名称', }, { 'fieldName': 'label', 'isImg': 0, 'order': 0, 'remarks': '标签', }, { 'fieldName': 'lon', 'isImg': 0, 'order': 0, 'remarks': '经度', }, { 'fieldName': 'lat', 'isImg': 0, 'order': 0, 'remarks': '纬度', }], articleType: [{ 'fieldName': 'name', 'isImg': 0, 'order': 0, 'remarks': '名称', }, { 'fieldName': 'label', 'isImg': 0, 'order': 0, 'remarks': '标签', }], }; /** * 将动表单态值生成需要的数据格式 * @param values * @returns {[]} */ createValues = (values) => { const { row } = this.state; const data = []; const newValues = { // 用新的对象承载提交的数据 ...values, }; const fieldNameData = []; // 保存fieldName值 const remarksData = []; // 保存remarks值 const isImgData = []; // 保存isImg值 const orderData = []; // 保存orderData值 const fieldName = RegExp(/fieldName/); const remarks = RegExp(/remarks/); const isImg = RegExp(/isImg/); for (const key in newValues) { if (fieldName.test(key)) { fieldNameData.push(newValues[key]); } } for (const key in newValues) { if (remarks.test(key)) { remarksData.push(newValues[key]); } } for (const key in newValues) { if (isImg.test(key)) { isImgData.push(newValues[key]); } } for (const key in newValues) { if (isImg.test(key)) { orderData.push(newValues[key]); } } fieldNameData.forEach((item, index) => { data.push({ fieldName: item, remarks: remarksData[index], isImg: isImgData[index], order: orderData[index], id: row.dataType ? row.dataType.id : '', }); }); return data; }; handleOk = e => { this.props.form.validateFields((err, values) => { if (!err) { const { row, isEdit } = this.state; const params = { dataType: { name: values.name, type: values.type, id: row.dataType ? row.dataType.id : '', }, typeFields: [], }; params.typeFields = this.createValues(values); if (isEdit) { editType(params).then(res => { if (res.code === 0) { message.info('修改成功'); this.setState({ visible: false, isEdit: false, }); this.fetchTypeList(); this.props.form.resetFields(); } }); } else { addType(params).then(res => { if (res.code === 0) { message.info('新增成功'); this.setState({ visible: false, isEdit: false, }); this.fetchTypeList(); this.props.form.resetFields(); } }); } } }); }; lookOrEditTypeModal = (flag, record) => { const { articleType, mapType } = this.state; if (flag === 'add') { //添加默认为文章模板 this.marketId = articleType.length + 1; //设置动态key标记长度 this.setState({ visible: true, row: { typeFields: articleType }, }); } else if (flag === 'edit') { this.setState({ visible: true, }); getType({ dataTypeId: record.id }).then(res => { if (res.code === 0) { this.marketId = res.data.typeFields.length + 1; //设置动态key标记长度 this.setState({ row: res.data, isEdit: flag === 'edit', }); } }); } else { this.setState({ lookVisible: true, }); getType({ dataTypeId: record.id }).then(res => { if (res.code === 0) { this.setState({ row: res.data, }); } }); } }; onChangeType = (value) => { const { form } = this.props; const { orderType, row, articleType, mapType } = this.state; this.props.form.resetFields(); const params = {}; if (value === 1) { //文章类型 params['typeFields'] = articleType; this.marketId = articleType.length + 1; } else { params['typeFields'] = mapType; this.marketId = mapType.length + 1; } this.setState({ row: params, orderType: value, }); }; //删除方法!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! removeFile = k => { const { form } = this.props; const keys = form.getFieldValue('keys'); if (keys.length === 1) { return; } form.setFieldsValue({ keys: keys.filter(key => key !== k), }); }; //添加方法!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! addFile = () => { const { form } = this.props; const keys = form.getFieldValue('keys'); const nextKeys = keys.concat(this.marketId++); form.setFieldsValue({ keys: nextKeys, }); }; judgeIsTemplet = (data) => { if (!data) { return false; } if ((data.fieldName === 'lat') || (data.fieldName === 'lon') || (data.fieldName === 'label') || (data.fieldName === 'name')) { return true; } }; handleValidator = (rule, val, callback) => { if (!val) { callback(); } let validateResult = /^[5A-Za-z0-9-\_]+$/.test(val); if (!validateResult) { callback('请输入正确表字段'); } callback(); }; columns = [ { title: '类型名称', dataIndex: 'name', key: 'name', width: 500, }, { title: '所属类型', dataIndex: 'type', key: 'type', render: (text) => { return text === 1 ? '文章' : '地图'; }, }, { title: '操作', dataIndex: 'address', key: 'address', render: (text, record) => { return <li> <Button type='link' onClick={() => this.lookOrEditTypeModal('look', record)}>查看</Button> <Button type='link' onClick={() => this.lookOrEditTypeModal('edit', record)}>编辑</Button> <Popconfirm title="确认删除?" onConfirm={() => this.deleteTypeClick(record)}> <Button type='link'>删除</Button> </Popconfirm> </li>; }, }, ]; render() { const { selectType, typeLoading, mock, row, isEdit, typeList, keyWord, lookVisible } = this.state; const { getFieldDecorator, getFieldValue } = this.props.form; let typeFields = row.typeFields || []; const initData = []; typeFields.forEach((item, index) => {//根据真实数据,设置默认keys数组 initData.push(index); }); getFieldDecorator('keys', { initialValue: initData }); //给表单增加keys字段,并设置默认值,这里编辑时候可以生成编辑回填的效果。 const keys = getFieldValue('keys'); const formItems = keys.map((k) => ( <Row gutter={12} key={k} className={styles.form_row}> <FormItem label="字段" key={`fieldName_${k}`}> {getFieldDecorator(`fieldName_${k}`, { initialValue: row.typeFields[k] ? row.typeFields[k].fieldName : '', validateTrigger: ['onChange', 'onBlur'], //校验子节点值的时机 rules: [{ required: true, message: '请输入英文字段!', }, { validator: this.handleValidator, }], })(<Input placeholder="请输入英文字段" max={30} disabled={this.judgeIsTemplet(row.typeFields[k])}/>)} </FormItem> <FormItem label="名称" key={`remarks_${k}`}> {getFieldDecorator(`remarks_${k}`, { initialValue: row.typeFields[k] ? row.typeFields[k].remarks : '', validateTrigger: ['onChange', 'onBlur'], rules: [{ required: true, message: '请输入中文名称!', }], })(<Input placeholder="请输入中文名称" disabled={this.judgeIsTemplet(row.typeFields[k])}/>)} </FormItem> <FormItem label="排序" key={`order_${k}`}> {getFieldDecorator(`order_${k}`, { initialValue: row.typeFields[k] ? row.typeFields[k].order : 0, })(<InputNumber style={{width:75}} placeholder="排序" />)} </FormItem> <FormItem label="图片" key={k}> {getFieldDecorator(`isImg_${k}`, { initialValue: row.typeFields[k] ? row.typeFields[k].isImg : 0, rules: [{ required: true, }], })(<Radio.Group disabled={this.judgeIsTemplet(row.typeFields[k])}> <Radio value={0}>否</Radio> <Radio value={1}>是</Radio> </Radio.Group>)} </FormItem> {!this.judgeIsTemplet(row.typeFields[k]) ? ( <Icon type="minus-circle" onClick={() => this.removeFile(k)} title='删除'/> ) : null} </Row> )); return ( <li className={styles.wrap_type}> <Modal title="类型管理" visible={this.state.visible} onOk={this.handleOk} onCancel={this.handleCancel} width={890} // className={styles.modal_type} maskClosable={false} > <Form layout='inline'> <Row style={{ textAlign: 'center', marginBottom: 14 }}> <FormItem label="选择类型"> {getFieldDecorator('type', { initialValue: row.dataType ? row.dataType.type : 1, rules: [{ required: true, }], })(<Select onChange={this.onChangeType} disabled={isEdit} style={{ width: 200 }}> <Option value={1}>文章类型</Option> <Option value={2}>地图类型</Option> <Option value={3} disabled={true}>文件类型</Option> </Select>)} </FormItem> <FormItem label="类型名称"> {getFieldDecorator('name', { initialValue: row.dataType ? row.dataType.name : '', rules: [{ required: true, message: '请输入类型名称!', }], })(<Input placeholder="请输入类型名称" style={{ width: 200 }}/>)} </FormItem> </Row> {formItems} <li style={{ margin: 'auto', textAlign: 'center' }}> <Button icon="plus" onClick={this.addFile} style={{ marginTop: 10 }}>新增字段</Button> </li> </Form> </Modal> </li> ); } } export default Index;
关键地方是设置一个marketID作为动态添加的key,然后用他的值作为动态key。(千万不要用数组的下标index来作为key)!
到此这篇关于react antd实现动态增减表单的文章就介绍到这了,更多相关react antd动态增减表单内容请搜索开心学习网以前的文章或继续浏览下面的相关文章希望大家以后多多支持开心学习网!
您可能感兴趣
- react常用设计模式(提高React界面性能的十个技巧)
- react怎么使用父组件(关于antd tree和父子组件之间的传值问题react 总结)
- yii2对比springboot(yii2.0框架使用 beforeAction 防非法登陆的方法分析)
- reactnative ios(详解React Native与IOS端之间的交互)
- linux虚拟内存实现需要哪六种机制(解析Linux高性能网络IO和Reactor模型)
- reactnative零基础入门到项目实战(用React Native制作一个简单的游戏引擎)
- react执行流程(React开启代理的2种实用方式)
- react组件之间通信(React传递参数的几种方式)
- react常见问题(React编程中需要注意的两个错误)
- react怎么绑定state(react纯函数组件setState更新页面不刷新的解决)
- react基础知识详解(如何深入理解React的ref 属性)
- react 使用实例(React+高德地图实时获取经纬度,定位地址)
- react源码教程(详解React 代码共享最佳实践方式)
- react怎样实现响应式计算属性(深入浅析React中diff算法)
- react代码质量检查(react如何实现一个密码强度检测器详解)
- react动态创建菜单并实现局部刷新(使用react-virtualized实现图片动态高度长列表的问题)
- 泰国旅游攻略(泰国旅游攻略必去景点)
- 数字藏品市场有多乱 周杰伦丢了 一只猴 ,损失超300万(数字藏品市场有多乱)
- 这里输入关键词(怎么输入关键词搜索)
- 得这个 难治病 的人太多了,300个人赶到杭州商量怎么办(得这个难治病的人太多了)
- 经度,世界时间腕表的灵魂(世界时间腕表的灵魂)
- 阿里最新财报公布 三季度营收增长3 ,将增加150亿美元回购额度 在美股价小涨(阿里最新财报公布)
热门推荐
- pythonlist列表讲解(Python中将两个或多个list合成一个list的方法小结)
- docker端口访问不了(docker设置了端口映射,不能访问的解决方案)
- ASP.NET批量下载文件
- php网页浏览功能的具体实现(php实现网页上一页下一页翻页过程详解)
- vue组件开发步骤(解析如何自动化生成vue组件文档)
- dedecms搜索功能怎么设置详细(取消dedecms 留言簿的验证码的方法)
- 部署ssis包提示更改保护级别(SSIS 延迟验证方法)
- python钉钉机器人(python钉钉机器人运维脚本监控实例)
- easyui layout 折叠后显示标题
- 自己怎么选网站服务器(网站空间服务器的正确选择方法)
排行榜
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9