问题

由于项目需要实现一个为经销商添加管理员的功能。如下图所示:

ant design vue 动态表单_数据结构


要求:

  • 至少添加一个管理员账号
  • 需要对管理员手机号做格式校验,非空校验,去重校验;管理员姓名做非空校验
  • 能够动态删除和添加管理员,并且格式化数据表单提交

实现

看到这里我们立马能够想到在通过数据实现,react语言的特殊性,通过数据反映dom的变化,所以对数据元素的添加和删除能够反映的dom元素。好了,原理知道了。接下来上代码
首先数据结构选择,数组的元素的数据结构如下:

constructor(props) {
    super(props);
    this.state = {
      managerList: [{name: "", phone: ""}],
    };
  }

然后在render方法中构造一个组件数组,如下。

render() {
	....
	let {managerList} = this.state;
    let managerNumber = managerList.length;
	let managerComps = managerList.map((el, index) =>{
      return (
        <span key={index}>
          <Row span={24}>
            <Col span={8}>
              <FormItem label="管理员姓名:" labelCol={{span: 10}} wrapperCol={{span: 12}}>
                  {getFieldDecorator(`name${index}`,{
                    initialValue: el.name,
                    rules: [{
                      required: true,
                      message: '请填写管理员姓名'
                    }]
                  })(
                    <Input />
                  )}
             </FormItem>
            </Col>
            <Col span={8}>
              <FormItem label="管理员手机号:" labelCol={{span: 8}} wrapperCol={{span: 12}}>
                  {getFieldDecorator(`phone${index}`,{
                    initialValue: el.phone,
                    rules: [{
                      required: true,
                      message: '请填写管理员手机号'
                    },{
                      pattern: /^1[3|4|5|7|8][0-9]\d{8}$/, message: '请输入正确的手机号'
                    },{
                      validator:this.phoneDuplicateValidator,
                    }],
                  })(
                    <Input />
                  )}
             </FormItem>
            </Col>
            <Col span={4} style={{marginTop:6}}>
             {index === 0 && managerNumber < 5 && <Button shape="circle" size="small" icon="plus" type="primary" style={{marginRight:10}} onClick={() => this.addManager()} />}
             {((managerNumber > 1 && index === 0) || index > 0)  && <Button shape="circle" size="small" icon="minus" type="default" onClick={() => this.delManager(index)} />}
           </Col>
           </Row>
        </span>
      )
    });

	return(
	<Form >
		<div className="ant-descriptions-title">
             管理员账号
       </div>
       <div>
         <div>
           {managerComps}
         </div>
       </div>
    </Form>   
	)
}

新增元素对应的addManager方法

collectManager = () =>{
    const {getFieldValue, resetFields} = this.props.form;
    const managerList = [];
    let managerNumber = this.state.managerList.length;
    for (let i = 0; i < managerNumber; i++){
      let name = getFieldValue(`name${i}`);
      let phone = getFieldValue(`phone${i}`);
      //!!!!重要,如果不加此方法,则会在删除元素时,getFieldDecorator的initalValue属性不生效的问题
      resetFields([`name${i}`,`phone${i}`]);
      managerList.push({name: name, phone: phone});
    }
    return managerList;
  }
  
  addManager = () =>{
    let managerList = this.collectManager();
    managerList.push({name: "", phone: ""});
    this.setState({managerList});
  }

删除元素对应的delManager方法

delManager = (index) =>{
    let managerList = this.collectManager();
    //删除指定index的元素
    managerList.splice(index,1);
    this.setState({managerList});
  }

元素去重校验方法

phoneDuplicateValidator = (rule, value, callback) =>{
    const {getFieldValue} = this.props.form;
    let managerNumber = this.state.managerList.length;
    let count = 0;
    for (let i = 0; i < managerNumber; i++){
      let phone = getFieldValue(`phone${i}`);
      if(phone === value){
        count++;
      }
    }
    count > 1 ? callback('管理员手机号码不能重复') : callback();
  }

实现后的效果自己可以本地看一下,之所以要写这篇博客,是因为我在实现的过程中遇到了删除元素了initialValue属性不生效的问题。导致的结果就是每次都是删除最后一个元素(因为数组长度减一了)
为了解决这个问题我尝试了很多种方法,比如:
1.设置一个visible属性,每次删除后重新挂载数组元素
2.手动调用form组件的setFieldsValue设置值。

以上方法尝试后全部失败了。由于我就想是什么原因导致了这个问题,仔细查看antd官方文档。发现了resetFields这一段描述

ant design vue 动态表单_ci_02


然后我便尝试在每次操作时,重置控件的值。此问题随即解决了。

总结

当我们使用getFieldDecorator并用initialValue设定初始值时,当我们改变组件的值时,组件表现出的值也改变了,但这个值并不是initialValue设定的,其是组件内部的state值保持的,如果需要继续用initialValue来设定组件的值,我们需要调用resetFields方法使initialValue有效。

前端路漫漫,作为一个后端开发工程师,写前端感觉更难,大家互勉!!!