使用antd form开发支持动态增减表单项,可选有初始值组件的一种实现方式(一)

本文介绍了一种基于Ant Design的动态表单组件封装方法,支持动态增减表单项,同时兼容无初值和有初值场景,适用于表单编辑与新增操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在使用antd form做动态表单开发时,官网有如下示例:

当添加表单项后:

使用此示例可以实现动态增加、减少表单项的功能,但是当我们编辑以前添加过的form表单时,该如何赋初值,又如何支持新增和编辑使用同一组件,即可以支持没有初值和有初值两种情况。本文分享了一种解决该问题的组件封装方式。

组件使用方式:

<TagComponent
tag={tag}
label='tag'
ref={ref => (this.tagRef = ref)}
/>

tag数据格式:

[{tagLabel:'label1',tagValue:'value1'}, {tagLabel:'label2',tagValue:'value2'}]

组件代码:

import React, {Component} from 'react';
import autobind from 'class-autobind';
import {Form, Input, Row, Col, Tooltip} from 'antd';
import './index.less';

const FormItem = Form.Item;
const prefixCls = 'tag-component';

class TagComponent extends Component{
    constructor(props){
        super(props);
        this.state = {};
	autobind(this, TagComponent.prototype);
        this.formItemHasLabel = {
            'labelCol': {'span': 12},
            'wrapperCol': {'span': 12}
        };
        this.formItemHasLabelPosition = {
            'labelCol': {'span': 0},
            'wrapperCol': {'span': 12, 'offset': 12}
        };
        this.formItemNoLabel = {
            'labelCol': {'span': 2},
            'wrapperCol': {'span': 18}
        };
        this.uuid = 0;
    }
     componentDidMount(){ // DidMount赋初值
        const {tag, form} = this.props;
        let formTag = [];
        for(let i = 0; i < tag.length; i ++){
            formTag = formTag.concat([tag[i].tagLabel, tag[i].tagValue]);
        }
        form.setFieldsValue({
            'formTag': formTag
        });
    }

    getInitialKeys(){
        const {tag} = this.props;
        let nextKeys = [];
        for(let i = 0; i < tag.length; i ++){
            nextKeys = nextKeys.concat([this.uuid, this.uuid + 1]);
            this.uuid = this.uuid + 2;
        }
        return nextKeys;
    }
    addTag(){
        const {form} = this.props;
        const keys = form.getFieldValue('keys');
        const nextKeys = keys.concat([this.uuid, this.uuid + 1]);
        this.uuid = this.uuid + 2;
        form.setFieldsValue({
            'keys': nextKeys
        });
    }
    removeTag(index){
        const {form} = this.props;
        // can use data-binding to get
        const keys = form.getFieldValue('keys');
        // We need at least one passenger
        if (keys.length === 0) {
            return;
        }
        // can use data-binding to set
        keys.splice(index - 1, 2);
        form.setFieldsValue({
            'keys': keys
        });
    }

    renderTagFormItems(){
        const {label} = this.props;
        const {getFieldDecorator, getFieldValue} = this.props.form;
        const initKeys = getFieldValue('keys');
        const InitialKeys = initKeys || this.getInitialKeys();
        getFieldDecorator('keys', {'initialValue': InitialKeys});
        const formItemHasLabel = this.formItemHasLabel;
        const formItemNoLabel = this.formItemNoLabel;
        const formItemHasLabelPosition = this.formItemHasLabelPosition;
        const keys = getFieldValue('keys');
        const formItems = keys.map((k, index) => (
            <Col span={index % 2 === 0 ? 14 : 10}>
                <FormItem
                    // eslint-disable-next-line no-nested-ternary
                    {...(index % 2 === 1 ? formItemNoLabel : index === 0 ? formItemHasLabel : formItemHasLabelPosition)}
                    // eslint-disable-next-line no-nested-ternary
                    label={index === 0 ? label : index % 2 === 0 ? '' : ' '}
                    required={false}
                    key={k}
                >
                    {getFieldDecorator(`formTag[${k}]`, {
                        'validateTrigger': ['onChange', 'onBlur'],
                        'rules': index % 2 === 0 ? [{
                            'required': true,
                            'whitespace': true,
                            'message': '必填,支持字母、数字、"."、"_"、"-",且不超过50字符',
                            'pattern': /^[A-Za-z0-9_\.-]{0,50}$/g
                        }] : [{
                            'required': true,
                            'whitespace': true,
                            'message':
                                '必填,支持字母、数字、"."、"_"、"-",且不超过50字符',
                            'max': 200
                        }]
                    })(
                        <Input
                            placeholder={index % 2 === 0 ? '请输入key' : '请输入value'}
                            className={index % 2 === 0 ? `${prefixCls}-input-left` : `${prefixCls}-input-right`}
                        />
                    )}
                    {keys.length > 0 && index % 2 === 1 ? (
                        <a href='javascript:;' className={`${prefixCls}-remove-btn`}>
                            <Tooltip placement='top' title='删除'>
                                <span className='dplicon_minus_circle_o' onClick={() => this.removeTag(index)} />
                            </Tooltip>
                        </a>
                    ) : null}
                </FormItem>
            </Col>
            )
        );
        return formItems;
    }
    render(){
        const {getFieldValue} = this.props.form;
        const keys = getFieldValue('keys');
        const {label} = this.props;
        const formItemLayout = keys && keys.length !== 0 ? this.formItemHasLabelPosition : this.formItemHasLabel;
        return(
            <Form>
                <Row>
                    {this.renderTagFormItems()}
                    <Col span={14} style={{'textAlign': 'center'}}>
                        <FormItem
                            {... formItemLayout}
                            // eslint-disable-next-line no-nested-ternary
                            label={keys && keys.length !== 0 ? '' : label}
                        >
                            <div className={`${prefixCls}-add-box`}>
                                <span className={`${prefixCls}-add-btn`} onClick={this.addTag}>
                                    <span className={`${prefixCls}-icon dplicon_plus_circle_o`} />
                                    <span className={`${prefixCls}-add-btn-text`}>添加</span>
                                </span>
                            </div>
                        </FormItem>
                    </Col>
                </Row>
            </Form>
        );
    }
}

export default Form.create()(TagComponent);

样式文件index.less

.tag-component{
  &-add{
    &-box{
      text-align: left;
    }
    &-btn{
      color: #0058ff;
      cursor: pointer;
      width: 100%;
      text-align: left;
      &-text{
        vertical-align: middle;
      }
    }
  }
  &-icon{
    vertical-align: middle;
    padding: 0 6px;
  }
  &-remove-btn{
    cursor: pointer;
    position: relative;
    transition: all .3s;
    margin-left: 4px;
  }
  &-input-left{
    width: 100%;
  }
  &-input-right{
    width: calc(~'100% - 20px');
  }
}

效果如下:

初始状态、无初始值或初始值为[]:

添加表单项后:

添加值或编辑(有初始值):

对于组件的解释及用法请看下篇文件《使用antd form开发支持动态增减表单项,可选有初始值组件的一种实现方式(二)》。

地址:https://blog.youkuaiyun.com/smk108/article/details/84554386

demo地址:https://blog.youkuaiyun.com/smk108/article/details/101784236

 

 

 

 

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值