antd4.0嵌套form.Item的使用

1,270 阅读2分钟

开头

前端开发中,如果你使用的是react框架去做开发,不可避免的会与AntDesign这个UI框架打交道。同时在很多实际业务开发中,常用到的当属Form和Table组件,特别是在管理系统这类项目中。前几天,笔者在解决公司项目的一个小bug时,刚好碰到了一个需要Form.Item嵌套来解决的问题。

问题🙋

测试提了一个bug需求,一个input输入框的数值回显的功能没有实现,查看代码时,一开始没有注意之前代码设计思路是formItem的表单值绑定给input的value,因此通过把input的defaultValue设置为productName的值,这个办法当然也是可以解决的。但是,不符合了之前代码的架构。

// 原代码
<Form.Item
label=“Product Name”
name="productName"
initialValue={undefined}
rules={[{ required: true, message: “Please Input”}
>
<div style={{ display: 'flex', alignItems: 'center' }}>
  <Input
    style={{
      width: 240,
      flex: 1,
      borderTopRightRadius: 0,
      borderBottomRightRadius: 0,
    }}
    disabled={readOnly}
    placeholder= “Please Input”
  />
  {i18nLanguageBizDicts.length > 1 && (
    <Tooltip placement="top" title=“Multilingual”>
      <MoreButton
        onClick={() => {
          if (!readOnly) {
            setVisible(true);
          }
        }}
        disabled={readOnly}
        style={{
          cursor: 'pointer',
          borderLeft: '0',
        }}
      />
    </Tooltip>
  )}
</div>
</Form.Item>

尝试

发现是input和另一个组件由于样式的需求,外面包裹了一个div,导致了外层的form.Item没有直接包裹到input组件,因此input没有绑定表单 此时想到了Fragment可以把多个元素整合返回一个元素,且不会影响样式,就使用了React.Fragment去对input和另一个组件进行包裹,结果还是没有解决这个问题。应该是Fragment只整合第一层的元素,因此在查看元素时input外层还是div,于是form.Item与input还是不是直接父子组件,没有绑定。去除div但Fragment上没有style属性,因此放弃这个想法💡

Pasted Graphic 2.png

解决🤓

在antd的官方文档可查阅到关于复杂控件(如需要对input/select添加文字描述或其他组件)的使用需要进行form.item的嵌套使用

Pasted Graphic 3.tiff

图源来自antd官方文档

可以理解为,外层form.item是用于控制样式内层form.item直接包裹组件用于解决数据绑定,因此对于form.item与包裹组件有关的属性值,需要写在内层的form.item属性上。同时,内层的form.item需要设置noStyle为true,这样不会对样式产生影响。

最后实现如下

    <Form.Item label={t('Product Name')}>
       <div style={{ display: 'flex', alignItems: 'center' }}>
          <Form.Item
            name="productName"
            initialValue={undefined}
            noStyle
            rules={[{ required: true, message: t('Please input') }]}
          >
            <Input
              style={{
                width: 240,
                flex: 1,
                borderTopRightRadius: 0,
                borderBottomRightRadius: 0,
              }}
              disabled={readOnly}
              placeholder={t('Please input')}
            />
          </Form.Item>
          ...

可以发现外层的form.item确实不参与数据传递和绑定,他包裹的直接子元素是div;内层的form.item设置name,rule等值参与input等数据绑定。

结语

在对formItem组件实现input或者其他组件的数据绑定,遇到非直接包裹关系,可以使用嵌套的formItem方案来解决。

入门前端小白第一次写文章,如有不足,恳请大家批评指正!感谢🙏🙏