React +Antd 表单动态添加文件上传

antd表单和上传组件

如果对antd的From和Upload组件不太熟悉,推荐去官网上先阅读下API。
Antd
本项目采用3.26.16版本

需求描述

表单项操作提示中,每个操作包含一个文本输入框,三个文件上传,还包含提示信息,每个提示信息,包含一个文本输入框,一个音频文件上传。提示信息可以动态增加和删除。操作提示也同理。文件回显时,通过返回的数组进行重新渲染。通过getFieldDecorator定义存储数组的名字,initialValue设置默认值。getFieldDecorator用于和表单进行双向绑定。

如有不想看文字描述,可以直接看下图:
在这里插入图片描述

首先,在本地的state中初始化了一个数组

boxList: [
        {
          toolStep: '名字',
          id: 0,
          promptSteps: [
            {
              toolStep: '工器具使用提示步骤1',
              id: 0,
            }
          ]
        }
      ], //boxList,

该数组中的id,新增时拼接于文件名后,保证getFieldDecorator中的id(文件名)具有唯一性。如果使用index拼接,在删除时会显示的错误的数据。

在这里插入图片描述
点击确定按钮后,将文件名和地址从文件数组中取出,传给后端。

this.props.form.validateFieldsAndScroll((err, values) => {
	if (!err) {
  		let submitData = {}
		submitData.toolShow = this.state.boxList.map((boxItem, idx) => {
           let data = {}
           data.name = boxItem.name
           data.demoSrf = values[`demoSrfList${boxItem.id}`][0].response.data.url
           data.realDemoSrf = values[`demoSrfList${boxItem.id}`][0].response.data.name
           data.demoLua = values[`demoLuaList${boxItem.id}`][0].response.data.url
           data.realDemoLua = values[`demoLuaList${boxItem.id}`][0].response.data.name
           data.demoSdf = values[`demoSdfList${boxItem.id}`][0].response.data.url
           data.realDemoSdf = values[`demoSdfList${boxItem.id}`][0].response.data.name
           data.promptSteps = boxItem.promptSteps.map((subItem, index) => {
             let subData = {}
             subData.toolStep = subItem.toolStep
             subData.toolIntroduction = subItem.toolIntroduction
             subData.toolAudio = values[`audioStepsName${boxItem.id}${subItem.id}`][0].response.data.url
             subData.realToolAudio = values[`audioStepsName${boxItem.id}${subItem.id}`][0].response.data.name
             subData.toolStepId = index
             return subData
           })
           return data
         })
 	}
});

点击编辑按钮,会把当前工具的数据传入。主要理清层级关系,将文件正确的存入其对应的文件数组。最后更新外层动态数组,渲染回显的数据。

showDrawer = (item, title) => {
if (item) {
   record = JSON.parse(JSON.stringify(item))
   let { dynamicPartList, synopsisList, boxList, operationList } = this.state
   // getToolLabel({ nameUrl: record.name }).then(res => {
   //   this.setState({ labelsList: res.data || [] })
   // })

   if (title === '编辑工器具' || title === '标签配置') {
     boxList = JSON.parse(JSON.stringify(item.toolShow))  
     boxList.forEach((boxItem, index) => {
       if (item.toolShow.length !== 0) {
         record[`demoSrfList${boxItem.id}`] = [{ name: item.toolShow[index].realDemoSrf, url: item.toolShow[index].demoSrf }]
         record[`demoLuaList${boxItem.id}`] = [{ name: item.toolShow[index].realDemoLua, url: item.toolShow[index].demoLua }]
         record[`demoSdfList${boxItem.id}`] = [{ name: item.toolShow[index].realDemoSdf, url: item.toolShow[index].demoSdf }]
         if (item.toolShow[index].promptSteps.length !== 0) {
           record.tipIds = item.toolShow[index].promptSteps
           item.toolShow[index].promptSteps.forEach((subItem, idx) => {
             record[`audioStepsName${boxItem.id}${subItem.id}`] = [{ name: item.toolShow[index].promptSteps[idx].realToolAudio, url: item.toolShow[index].promptSteps[idx].toolAudio }]
           })
         }
       }

     })
      this.setState({
          drawerTitle: title,
          boxList,
          editData: record || {}
        })
     }

通过遍历这个demoSrfList这个文件数组,将name和url展现在界面上,并且存入response中。

<Form.Item>
   {getFieldDecorator(`demoSrfList${boxitem.id}`, {
     initialValue: (editData[`demoSrfList${boxitem.id}`] || []).map((f, index) => ({
       // 为了提供给上传组件回显
       uid: index,  // 这是上传组件规定的文件唯一标识,内部会提供给Form以便正常渲染回显列表
       name: f.name,
       status: 'done',
       url: f.url,
       response: {
         data: {
           name: f.name,
           url: f.url,
         }
       }
     })),
     valuePropName: 'fileList',
   })(
     <Upload name="file" {...upLoadProps} accept=".srf">
       <Button>
         <Icon type="upload" />上传文件
     </Button>
       <p style={{ fontSize: '12px', color: '#999' }}>支持上传格式srf</p>
     </Upload>
   )}
 </Form.Item>

效果如下:
在这里插入图片描述
但是这样还不算完。我在新增的时候还发现一个问题。假如开始我新增了很多提示,每个提示都上传了文件。但是最后我觉得有点多了,想删除一个提示,这个时候,其它的所有文件都消失了。所以,在上传文件的时候,需要通过onChange事件,将文件名进行存储。我认为这里不需要存url,因为这里不用点击文件。

<Upload name="file" {...upLoadProps} accept=".srf" onChange={(f) => {
  if (f.file.status === 'done') {
     this.state.editData[`demoSrfList${boxitem.id}`] = [{ name: f.file.response.data.name }]
   }
 }}>
   <Button>
     <Icon type="upload" />上传文件
 </Button>
   <p style={{ fontSize: '12px', color: '#999' }}>支持上传格式srf</p>
</Upload>

再提一下这个Upload中的accept属性。它只是帮你 默认选择了上传文件类型,并没有做校验。所以要进行手动校验。像校验图片那样,在Upload的beforeUpload方法中,将文件的名字进行截取,通过后缀名判断文件是否合法。

下面是上传图片前校验:

  //上传图片前校验
  beforeUpload(file) {
    const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'image/jpg';
    if (!isJpgOrPng) {
      message.error('文件格式错误,请重新选择');
    }
    const isLt2M = file.size / 1024 / 1024 < 2;
    if (!isLt2M) {
      message.error('文件太大,请重新选择');
    }
    return isJpgOrPng && isLt2M;
  }

以上只是我个人想法,如有不足,欢迎指出,感谢你的阅读!

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
React中,清空表单可以通过Antd的Form组件提供的`resetFields`方法来实现。具体步骤如下: 1. 在表单的父组件中引入`Form`组件,并将表单的所有控件都用`Form.Item`包裹起来,每个`Form.Item`需要设置`name`属性,这个属性值需要与`getFieldDecorator`方法中的`id`参数保持一致。 ```jsx import { Form, Input, Button } from 'antd'; class MyForm extends React.Component { render() { const { getFieldDecorator } = this.props.form; return ( <Form> <Form.Item label="用户名" name="username"> {getFieldDecorator('username')(<Input />)} </Form.Item> <Form.Item label="密码" name="password"> {getFieldDecorator('password')(<Input.Password />)} </Form.Item> <Form.Item> <Button type="primary" onClick={this.handleSubmit}>提交</Button> <Button onClick={this.handleReset}>重置</Button> </Form.Item> </Form> ); } } ``` 2. 在表单的父组件中定义`handleSubmit`和`handleReset`方法。`handleSubmit`方法用于提交表单,`handleReset`方法用于清空表单。 ```jsx class MyForm extends React.Component { handleSubmit = e => { e.preventDefault(); this.props.form.validateFields((err, values) => { if (!err) { console.log('Received values of form: ', values); } }); }; handleReset = () => { this.props.form.resetFields(); }; render() { //... } } ``` 3. 在表单的父组件中将`MyForm`组件包裹在`Form.create`函数中,生成一个新的高阶组件,并将其导出。 ```jsx const WrappedMyForm = Form.create({ name: 'my_form' })(MyForm); export default WrappedMyForm; ``` 这样,当用户点击表单中的“重置”按钮时,表单中的所有控件都会被清空。如果想要清空表单中的某一个控件,可以通过`setFieldsValue`方法来清空,具体可见前面的回答。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值