需求:现有一个form表单,但是其中一个元素比较复杂,并不是简单的输入框或者下拉框之类的.但是我又希望能通过form.validateFields().then()去获得它的值,就不需要在当前页面写大量相关的逻辑了.

 

方案:将其封装成自动绑定值的组件

      (1)form.item会给组件的props注册两个关键属性,

             value:value是form.item对应的name属性的值,可用作默认值以及返显,

             onChange函数.:用于监听value元素值的变化,并将其传给form.item使其可以通过相关api获得其值.

      (2)注意value值不一定和页面渲染的数据相同.比如:我需要同时渲染三个input,那我页面渲染的时候需要一个数组,但是可能传给后端的时候是用","这类符合分开的.所以onCange()传递的值最好分开处理.

 

如:

<Form.Item  name='name'>
   <InputList ></InputList >
<Form.Item>

 

子组件InputList内部代码(简易版):

 (这段代码是临时在博客中编写的,主要是展示value和onChange的功能,不确保能正确执行)

const InputList = (props)=>{
 const { value ,onChange } =props //value 是form表单中"name"对应的字段值

const getValue = ()=>{
  let newList = JSON.parse(JSON.stringify(value )) //深拷贝一波,防止对原数据造成影响
  let value = newList .join(',')
   onChange(value)

}
useEffect((item,index)=>{
getValue ()  //传递值的时机可以自己把握,可以是点击事件也可以是其他事件
},[value.length])
return <>
        {value ?.length>0 && value.map((item,index)=>{
         return <div key = {index}>{item}</div>    //如果组件内部有增删等功能,可以不建议用index,可以在渲染之前给每个iten绑定一个特定的key,不然会出现删除之后出现相同key,然后dom元素不重新渲染的问题      
})}
   </>
}

 

现在结合实际情景说明一下子组件内部代码:

如图为一个可以增删改的input列表

如何自定义antd组件form表单中Form.Item里的内容组件_form表单

实际代码:

(这段代码有很大的优化空间,因为刚开始没考虑清楚,后续补补填填导致代码逻辑越来越复杂,不过主要是展示自定义form.item元素的实现,具体业务逻辑可以省略)

/*
*先解释一下下面会出现的容易混淆的几个变量分别代表什么
*dataList:用于渲染页面,增删的时候改变,输入框内容变更的时候不变,因为改变它会导致页面重新渲染,输入框失去焦点,每次就只能输入一个字符然后又得重新获得焦点
*datas:实际的已经改变的,用于下次页面更新的数据保留.所以实际上跟页面看上去是一样的值
*dataLists:下次实际更新的值,这里是根据datas和dataList来判断的,绝大部分情况是跟datas一致的
*dataValue :onChange()传递的值,因为业务需求,做了非空去除,页面实际上可以有空输入框,但是提交的时候不能有空值
*
*/

let datas = [''];
let disable = false;
let value = '';
let dataValue = undefined;
let inputIndex = 0;
class InputList extends React.Component {
  formRef = React.createRef();
  state = {
    dataList: [{ data: '', indexe: 0, default: true }],
    value: [],
  };
  static getDerivedStateFromProps(nextProps, prevState) {
    // Should be a controlled component.
    if ('value' in nextProps) {
      let { value } = nextProps;
      if (_.isEqual(value, prevState.origin)) {
        return null;
      }
      if (!_.isArray(value)) {
        if (!value) value = [];
        else value = [value];
      }
//因为这个生命周期会监听每次变化,所以必须严格控制其条件
      if (
        value &&
        prevState?.dataList[0]?.default 
      ) {
        datas = cloneDeep(value);
        dataValue = cloneDeep(value);
        let file = [];
        file = value.map((v, i) => {
          return { data: v, index: i };
        });
        // }
        return {
          dataList: file,
        };
      } else {
        return null;
      }
    }
    return null;
  }

  componentDidMount() {
    const { disabled, value } = this.props;
    disable = disabled;
  }
  triggerChange = (files, index) => {
    const onChange = this.props.onChange;
    if (datas === undefined) {
      datas = [];
    }
    if (dataValue === undefined) {
      dataValue = [];
    }
    datas[index] = files.target.value;
    dataValue[index] = files.target.value;
    value = files.target.value;
    inputIndex = index;
    if (onChange) {
      dataValue = dataValue.filter((item) => item !== null && item !== '');
      if (dataValue.length === 0) {
        dataValue = undefined;
      }
      onChange(dataValue);
    }
  };

  addInput = () => {
    const { dataList } = this.state;
    let arr = dataList;
    arr.push({
      data: '',
      index: dataList.length,
    });
    this.setState({
      dataList: arr,
    });
    if (datas === undefined) {
      datas = [];
    }
    if (dataValue === undefined) {
      dataValue = [];
    }
    datas.push('');
    dataValue.push('');
  };
  delIputn = (index) => {
    let { dataList } = this.state;
    let arr = [];
    let dataLists = [];
    if (datas === undefined) {
      datas = []; //因为有undefined的情况,所以预先处理
    }
    if (dataValue === undefined) {
      dataValue = []; //因为有undefined的情况,所以预先处理
    }
   
    dataValue.splice(index, 1);
    datas.splice(index, 1);
    dataLists =
      datas?.length > 0
        ? datas.map((item, index) => (item = { data: item, index: item.index }))
        : dataList;
    dataLists?.length > 0 &&
      dataLists.forEach((item, index1) => {
        arr.push(item);
      });
    this.setState({
      dataList: dataLists,
    });
    const onChange = this.props.onChange;
    // let datas = cloneDeep(dataList);
    if (onChange) {
      dataValue = dataValue.filter((item) => item !== null && item !== '');
      if (dataValue.length === 0) {
        dataValue = undefined; //设置成undefined是为了让校验不通过
      }
      onChange(dataValue);
    }
  };
  render() {
    const { dataList } = this.state;
    const { disabled } = this.props;
    return (
      <>
        <div>
          {dataList.map((item, index) => {
            return (
              <div style={{ display: 'flex', marginBottom: '10px' }}>
                <Input
                  onChange={(value) => this.triggerChange(value, index)}
                  // value={item.data}
                  key={index + item.data + item.index}
                  disabled={disabled}
                  defaultValue={item.data}
                ></Input>
                {(index > 0 || dataList?.length > 1) && !disabled ? (
                  <div
                    className={styles.delBox}
                    onClick={() => this.delIputn(index)}
                  >
                    删除
                  </div>
                ) : (
                  <div className={styles.delBox}></div>
                )}
              </div>
            );
          })}
        </div>

        {!disabled ? (
          <div className={styles.addBox} onClick={() => this.addInput()}>
            添加管制名单
          </div>
        ) : null}
      </>
    );
  }
}

export default InputList;