一、 React 结合 Antd 实现图片上传
- 引入所需相关的组件和文件,代码如下所示:
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { Upload, Icon, Modal, message } from 'antd'
import { reqDeleteImg } from '../../api'
import { BASE_IMG_URL } from '../../utils/constants'
- 创建
PicturesWall
图片上传组件,定义初始化的 state
,previewVisible
为标识是否显示大图预览 Modal
,默认为 false
。previewImage
为大图的 url
,默认为空。fileList
为所有已上传图片文件对象的数组,默认为空数组,代码如下所示:
state = {
previewVisible: false,
previewImage: '',
fileList: [],
}
- 在
PicturesWall
组件中创建三个方法,getImgs
是获取所有已上传图片文件名的数组,handleCancel
是隐藏 Modal
,handlePreview
是预览大图图片。对于获取上传图片数组,可以直接遍历 state
中的 fileList
得到。对于隐藏 Modal
,通过 setState
设置 previewVisible
为 false
就可以。对于预览大图图片,通过 setState
设置 previewImage
,显示指定 file
对应的大图,同时设置 previewVisible
为 true
就可以,代码如下所示:
getImgs = () => {
return this.state.fileList.map(file => file.name)
}
handleCancel = () => this.setState({ previewVisible: false })
handlePreview = file => {
this.setState({
previewImage: file.url || file.thumbUrl,
previewVisible: true,
})
}
- 在
handleChange
方法中,去实现图片上传的功能。file
是当前操作的图片文件(上传/删除),fileList
是所有已上传图片文件对象的数组。判断当前 file
的 status
,如果是 done
,说明当前操作是上传图片。通过 file.response
获取 result
。如果 result.status
为 0,说明图片上传成功,从结果中结构获取 name
和 url
,反之则图片上传失败。如果当前 file
的 status
为 removed
,说明当前操作是删除图片,调用删除图片的接口。如果 result.status
为 0,说明删除图片成功,反之则删除失败。最后,通过 setState
设置 fileList
,在操作(上传/删除)过程中更新 fileList
状态,代码如下所示:
handleChange = async ({ file, fileList }) => {
if (file.status === 'done') {
const result = file.response
if (result.status === 0) {
message.success('上传图片成功')
const { name, url } = result.data
file = fileList[fileList.length - 1]
file.name = name
file.url = url
} else {
message.error('上传图片失败')
}
} else if (file.status === 'removed') {
const result = await reqDeleteImg(file.name)
if (result.status === 0) {
message.success('删除图片成功!')
} else {
message.error('删除图片失败!')
}
}
this.setState({ fileList })
}
- 在
render
中,通过 this.state
解构获取 previewVisible
、previewImage
和 fileList
,使用 Upload
组件实现图片上传和删除的显示。action
是上传图片的接口地址,accept
是只接收图片格式,name
是请求参数名,listType
是卡片样式,fileList
是所有已上传图片文件对象的数组,onPreview
是点击文件链接或预览图标时的回调,onChange
是上传文件改变时的状态,代码如下所示:
render() {
const { previewVisible, previewImage, fileList } = this.state
const uploadButton = (
<div>
<Icon type="plus" />
<div>Upload</div>
</div>
);
return (
<div className="clearfix">
<Upload
action="/manage/img/upload"
accept="image/*"
name="image"
listType="picture-card"
fileList={fileList}
onPreview={this.handlePreview}
onChange={this.handleChange}
>
{fileList.length >= 8 ? null : uploadButton}
</Upload>
<Modal visible={previewVisible} footer={null} onCancel={this.handleCancel}>
<img alt="example" style={{ width: '100%' }} src={previewImage} />
</Modal>
</div>
)
- 在
addUpdate
组件中去使用图片上传组件 PicturesWall
。在这里就会涉及到组件传值的问题。子组件调用父组件的方法是将父组件的方法以函数属性的形式传递给子组件, 子组件就可以调用。父组件调用子组件的方法是在父组件中通过 ref
得到子组件标签对象(也就是组件对象), 调用其方法。所以,我们就可以通过 ref
去实现组件传值。首先,创建 ref
容器,在 constructor
中,通过 React.createRef()
进行创建用来保存 ref
标识的标签对象的容器,代码如下所示:
constructor (props) {
super(props)
this.pw = React.createRef()
this.editor = React.createRef()
}
- 然后,在
addUpdate
组件中,将 ref
容器交给需要获取的标签元素,进行使用,代码如下所示:
<Item label="商品图片">
<PicturesWall ref={this.pw} imgs={imgs}></PicturesWall>
</Item>
- 最后,通过
ref
容器读取标签元素。在表单提交的时候,去进行读取,代码如下所示:
const imgs = this.pw.current.getImgs()
- 在
PicturesWall
组件中,通过 prop-types
中的 PropTypes
进行检测由父组件传入的 imgs
的数据,由 PropTypes.array
判断传入的 imgs
必须为数组。在 constructor
中,通过 this.props
获取传入的 imgs
属性。判断只有当 imgs
存在 并且 imgs.length
要大于 0,将 imgs
进行 map
遍历得到 fileList
。uid
是每个 file
都有自己唯一的 id
,name
是图片文件名,status
是图片状态: done
是已上传, uploading
是正在上传中, removed
是已删除。最后,通过 setState
初始化状态,previewVisible
为 false
,previewImage
为空,fileList
为图片上传数组,代码如下所示:
static propTypes = {
imgs: PropTypes.array
}
constructor (props) {
super(props)
let fileList = []
const { imgs } = this.props
if (imgs && imgs.length>0) {
fileList = imgs.map((img, index) => ({
uid: -index,
name: img,
status: 'done',
url: BASE_IMG_URL + img
}))
}
this.setState({
previewVisible: false,
previewImage: '',
fileList
})
}
二、React 结合 Antd 实现图片上传的实现
React
结合 Antd
实现图片上传的实现,完整代码如下所示:
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { Upload, Icon, Modal, message } from 'antd'
import { reqDeleteImg } from '../../api'
import { BASE_IMG_URL } from '../../utils/constants'
export default class PicturesWall extends Component {
static propTypes = {
imgs: PropTypes.array
}
state = {
previewVisible: false,
previewImage: '',
fileList: [],
}
constructor (props) {
super(props)
let fileList = []
const { imgs } = this.props
if (imgs && imgs.length>0) {
fileList = imgs.map((img, index) => ({
uid: -index,
name: img,
status: 'done',
url: BASE_IMG_URL + img
}))
}
this.setState({
previewVisible: false,
previewImage: '',
fileList
})
}
getImgs = () => {
return this.state.fileList.map(file => file.name)
}
handleCancel = () => this.setState({ previewVisible: false })
handlePreview = file => {
this.setState({
previewImage: file.url || file.thumbUrl,
previewVisible: true,
})
}
handleChange = async ({ file, fileList }) => {
if (file.status === 'done') {
const result = file.response
if (result.status === 0) {
message.success('上传图片成功')
const { name, url } = result.data
file = fileList[fileList.length - 1]
file.name = name
file.url = url
} else {
message.error('上传图片失败')
}
} else if (file.status === 'removed') {
const result = await reqDeleteImg(file.name)
if (result.status === 0) {
message.success('删除图片成功!')
} else {
message.error('删除图片失败!')
}
}
this.setState({ fileList })
}
render() {
const { previewVisible, previewImage, fileList } = this.state
const uploadButton = (
<div>
<Icon type="plus" />
<div>Upload</div>
</div>
);
return (
<div className="clearfix">
<Upload
action="/manage/img/upload"
accept="image/*"
name="image"
listType="picture-card"
fileList={fileList}
onPreview={this.handlePreview}
onChange={this.handleChange}
>
{fileList.length >= 8 ? null : uploadButton}
</Upload>
<Modal visible={previewVisible} footer={null} onCancel={this.handleCancel}>
<img alt="example" style={{ width: '100%' }} src={previewImage} />
</Modal>
</div>
);
}
}