Antd 4 Upload 图片上传(前端篇)

简介

记录一下第一次使用Ant DesignUpload组件上传图片到后端服务器的基本流程和思路。

前端使用了React + Antd,后端使用NodejsExpress

主要介绍AntdUpload组件的照片墙,也就是上传多张图片。

example

Ant Design官方Upload教程地址:Antd Upload 组件

实现

1. 简单的render

import React, { Component } from 'react'
import { Card, Upload } from 'antd'
import { PlusOutlined } from '@ant-design/icons'

class Example extends Component {

  render() {
    return (
      <Card title='图片上传'>
        <Upload listType='picture-card'>
          <PlusOutlined />
          <div style={{ marginTop: 8, color: '#666' }}>上传图片</div>
        </Upload>
      </Card>
    )
  }
}

export default Example

也就是先做一个基本的Upload组件样子:

1

Card组件是为了案例的样式效果好一点。现在的Upload组件还不具有上传的功能,只是简单的使用,listType属性是Upload组件的显示效果,有picture-cardpicturetext这三个属性值,对应的效果可在Antd官网查看。

2. 上传功能

Upload组件添加action属性,就可以利用FormData表格数据的格式提交到后端服务器地址。

// 省略部分代码

// 后端API
const SERVER_URL = 'http://localhost:8000'
const UPLOAD_URL = `${SERVER_URL}/upload`

// render 中部分代码
<Upload
  listType='picture-card'
  action={UPLOAD_URL}
>
  <PlusOutlined />
  <div style={{ marginTop: 8, color: '#666' }}>上传图片</div>
</Upload>

3. 查看图片

  1. 添加一个用于查看图片的Modal对话框组件,设置组件的footer属性为null来隐藏对话框对应的确认和取消按钮;然后在Modal组件中包含一个原生的img标签用来显示图片,设置对应的srcalt属性。
  2. Upload组件中设置onPreview属性,用户点击查看图片按钮就会触发这个函数。在onPreview中设置组件的几个状态。

onPreview

import React, { Component } from 'react'
import { Card, Upload, Modal } from 'antd'
import { PlusOutlined } from '@ant-design/icons'

// 后端API
const SERVER_URL = 'http://localhost:8000'
const UPLOAD_URL = `${SERVER_URL}/upload`

class Example extends Component {
  state = {
    previewVisible: false,
    previewImage: '',
    previewImageName: ''
  }

  // 显示用于查看图片的 Modal 组件
  showPreview = file => {
    this.setState({
      previewVisible: true,
      previewImage: file.url || file.thumbUrl,
      previewImageName: file.name
    })
  }

  // 隐藏用于查看图片的 Modal 组件
  hidePreview = () => {
    this.setState({
      previewVisible: false
    })
  }

  render() {
    const { previewVisible, previewImage, previewImageName } = this.state
    return (
      <Card title='图片上传'>
        <Upload
          listType='picture-card'
          action={UPLOAD_URL}
          onPreview={this.showPreview}
        >
          <PlusOutlined />
          <div style={{ marginTop: 8, color: '#666' }}>上传图片</div>
        </Upload>
        {/* 用于查看图片的 Modal 对话框 */}
        <Modal
          visible={previewVisible}
          footer={null}
          onCancel={this.hidePreview}
        >
          <img
            src={previewImage}
            alt={previewImageName}
            style={{ width: '100%' }}
          />
        </Modal>
      </Card>
    )
  }
}

export default Example

4. 处理服务端上传结果

前面实现的上传图片,虽然通过action属性向服务端发送了请求,但是我们并没有对服务端返回的上传结果进行处理。也就是说,我们没有将服务端的结果反馈给用户,用户并不清楚服务端是否也上传成功,图片是否成功存在服务端。

首先给Upload组件添加onChange属性:onChange={this.handleChange}。然后我们定义handleChange函数:

// 处理图片上传
handleChange = ({ file, fileList }) => {
  const { status, response } = file
  // 上传完成?
  if (status === 'done') {
    // 服务端返回JSON:{ok: true/false, message: "", data: ""}
    const { ok, message: msg, data } = response
    if (ok) {
      // antd的message方法
      message.success(msg)
    } else {
      message.error(msg)
    }
  }
  this.setState({ fileList })
}

那么这样就有了简单的反馈提示:

upload-image

5. 优化 fileList(可选)

上传了图片后,通过React开发工具插件看看组件状态statefileList中添加了完整的file对象,我觉得没这个必要吧,因为上传完成后已经用不到里面的一些属性,那么我就在onChange属性对应的函数中手动做个简单的对象添加到fileLIst吧。

fileList-state

写一个optimizeFileList函数吧:

// fileList中file文件对象的属性太多了,上传完成后只留必要的属性
optimizeFileList = (data, fileList) => {
  // 后端数据中取得图片的名称和url地址
  const { name, url } = data
  // 去除上传完成后自动添加到fileList的file对象
  const file = fileList.pop()
  // 拿到需要的uid
  const { uid } = file
  // 创建一个只有必须属性的file对象
  const newFile = { uid, name, url: `${SERVER_URL}/${url}` }
  fileList.push(newFile)
}

// 处理图片上传
handleChange = ({ file, fileList }) => {
  const { status, response } = file
  // 上传成功?
  if (status === 'done') {
    const { ok, message: msg, data } = response
    if (ok) {
      this.optimizeFileList(data, fileList)
      message.success(msg)
    } else {
      message.error(msg)
    }
  }
  this.setState({ fileList })
}

现在上传图片后我们看一下组件的state,只保留了uidnameurl

optimize-fileList

6. 删除功能

点击删除时不只是清除state就完了,还需要删除服务端存的图片。设置onRemove属性绑定handleRemove函数,在函数里向后端发送删除请求,根据后端返回的结果再做处理。

// 添加一个后端API
const DELETE_URL = `${SERVER_URL}/delete`

// 类组件中:
handleRemove = async file => {
  // 有url属性说明上传到了服务器
  const { url } = file
  if (url) {
    const path = url.replace(`${SERVER_URL}/`, '')
    const response = await fetch(DELETE_URL, {
      method: 'delete',
      headers: { 'content-type': 'application/json' },
      body: JSON.stringify({ path })
    })
    const { ok, message: msg } = await response.json()
    if (ok) {
      message.success(msg)
    } else {
      message.error(msg)
      return false
    }
  }
}

补充:Form自动收集Upload数据

Form组件中使用Uploda组件让用户上传图片,在表单提交的时候我们也想让Form自动收集到Upload组件的数据,我们需要配合Form组件提供给子组件props中的onChange方法来完成。

1. 修改 Upload 组件

Upload组件的onChange属性绑定的handleChange方法中调用propsonChange方法:

handleChange = ({ file, fileList }) => {
  const { status, response } = file
  // 上传成功?
  if (status === 'done') {
    const { ok, message: msg, data } = response
    if (ok) {
      this.optimizeFileList(data, fileList)
      // 调用 onChange 方法
      this.props.onChange(fileList)
      message.success(msg)
    } else {
      message.error(msg)
    }
  }
  this.setState({ fileList })
}

2. 在 Form 组件中使用 Upload

import React, { Component } from 'react'
import { Card, Form, Input, Button } from 'antd'
// 引入写好的Upload组件
import UploadImage from './UploadImage'

const { Item } = Form

class FormExample extends Component {
  handleSubmit = values => {
    console.log(values)
  }

  render() {
    return (
      <Card title='表单案例'>
        <Form onFinish={this.handleSubmit}>
          <Item label='商品名称' name='name'>
            <Input />
          </Item>
          <Item label='商品图片' name='images'>
            <UploadImage />
          </Item>
          <Button type='primary' htmlType='submit'>提交</Button>
        </Form>
      </Card>
    )
  }
}

export default FormExample

提交数据我们就收集到Upload组件的fileList数据,然后自己用需要的数据提交给后端就OK。

form-example


版权声明:

Anand's Blog文章皆为站长Anand Zhang原创内容,转载请注明出处。

包括商业转载在内,注明下方要求的文章出处信息即可,无需联系站长授权。

请尊重他人劳动成果,用爱发电十分不易,谢谢!

请注明出处:

本文出自:Anand's Blog

本文永久链接:https://anandzhang.com/posts/frontend/14