antd pro开发踩坑

934 阅读2分钟

第一次使用antd pro框架,第一个想法是:居然有这么一个对表单数据处理方便的框架,开心的一逼,然后就开始了坎坷的开发之路。话不多说上代码。

我要开发的功能模块如下图所示:自定义地址组件开发. image.png 提交的数据格式为:

// form表单的数据格式
params = {
    companyAddressList: [{
        country: '中国',
        province: '浙江',
        city: '杭州',
        area: '西湖区',
        street: '*****',
        postcode: '*****',
        defaultStatus: false,
    },{
        country: '中国',
        province: '浙江',
        city: '杭州',
        area: '西湖区',
        street: '*****',
        postcode: '*****',
        defaultStatus: false,
    }],
    billAddressList: [{
        country: '中国',
        province: '浙江',
        city: '杭州',
        area: '西湖区',
        street: '*****',
        postcode: '*****',
        defaultStatus: false,
    }, ],
    receiptAddressList: []
}

首先,表单最外层需要 ProForm 标签,用来进行最后的提交操作。

<ProForm
  className="hy-form-container"
  formRef={formRef}
  name="hy-form"
  layout="vertical"
  onFinish={onSumitForm} // 提交方法
>
  <HYSchemaForm formRef={formRef} /> // 在该组件里面写子方法
</ProForm>

我是用 Segmented 来模拟客户地址、账号地址和收货地址。

const addressNameList = [
  {
    title: '客户地址',
    dataIndex: 'companyAddressList',
  },
  {
    title: '账单地址',
    dataIndex: 'billAddressList',
  },
  {
    title: '收货地址',
    dataIndex: 'receiptAddressList',
  },
];

const { formRef } = props;
const [activeAddressType, setActiveAddressType] = useState('客户地址');

const  addressOptions = addressNameList.map((item) => {
    return item.title;
});

<Segmented
    size="large"
    options={addressOptions}
    onChange={(value: string | number) => {
      setActiveAddressType(value as string);
    }}
/>

下面就是列表的渲染。需要注意的点有这么几个(详见代码注释):

const actionRef = [useRef(), useRef(), useRef()];

<div className="address-form-list">
  {addressNameList && addressNameList.length ? 
    addressNameList.map((item, index) => {
      const isShowFormList = activeAddressType === item.title;

      return (
        <ProFormList
          actionRef={actionRef[index]}  // addressNameList有三个数据所以useRef()需要定义三次
          key={item.dataIndex}
          name={item.dataIndex}   // name用上传数据的字段名比如companyAddressList
          copyIconProps={false}   // 复制按钮不展示
          initialValue={[{}]}     // 初始化数据
          fieldExtraRender={(fieldAction) => {
            // 自定义新增地址按钮
            return (
              <Button icon={<PlusOutlined />} onClick={() => fieldAction.add({})}>
                新增地址
              </Button>
            );
          }}
          creatorButtonProps={false}
          actionRender={(field) => {
            return [
            
              /**
               *  这里会遇到一个大坑
               *  key值要用field.name,而不用field.key
               *  field.name相当于数组的index下标
              */
              
              <a
                style={{ color: '#FF4218' }}
                key={field.name}
                onClick={() => actionRef[index]?.current?.remove(field.name)}
              >
                <DeleteOutlined />
                删除
              </a>,
            ];
          }}
          deleteIconProps={false}
          style={{ display: isShowFormList ? 'flex' : 'none' }} // 模拟列表的显示隐藏
        >
          // 这块代码也很重要:将index传到子模块中,当做子模块的key
          {(
            meta,
            // 当前的行号
            groupIndex: number,
          ) => {
            return renderGroups(groupIndex);
          }}
        </ProFormList>
      );
    })
  : null}
</div>

最后,将group内容渲染出来,其中要注意的是,name是对应的字段名称。

// 获取对应字段的列表数据并返回
const getAllAddressInfo = (list: any) => {
    return list.map((item: any) => {
      return formRef?.current?.getFieldValue(item);
    });
};

// 此处是将companyAddressList数据复制到另外两个数组中
const setAllAddress = (index: number) => {
    const dataIndexList = addressNameList.map((item) => {
      return item.dataIndex;
    });

    const [companyAddressList, billAddressList, receiptAddressList] = getAllAddressInfo(dataIndexList);

    formRef.current?.setFieldsValue({
      billAddressList: billAddressList.concat(companyAddressList[index]),
      receiptAddressList: receiptAddressList.concat(companyAddressList[index]),
    });
};

const renderGroups = (index: any) => {
    return (
      <ProForm.Group key={index}>
        <ProFormText name="country" label="国家" width={120} />
        <ProFormText name="province" label="省份" width={100} />
        <ProFormText name="city" label="市" width={100} />
        <ProFormText name="area" label="区" width={100} />
        <ProFormText name="street" label="街道详细地址" width={260} />
        <ProFormText name="postcode" label="邮编" width={150} />
        <div className="address-container">
          <ProFormCheckbox name="defaultStatus" label=" ">
            默认地址
          </ProFormCheckbox>

          {activeAddressType === addressNameList[0]?.title ? (
            <Checkbox
              onChange={() => {
                setAllAddress(index);
              }}
            >
              同时设置为账单地址/公司地址
            </Checkbox>
          ) : null}
        </div>
      </ProForm.Group>
    );
};

了解pro的写法,在表单开发中还是非常方便的。