最近使用到了 ant design 上传组件,用到了手动上传这部分,折腾了两三天,最后勉强摸通了手动上传的一些门路,记录一下。
手动上传显示缩略图
手动上传的预览选择 缩略图预览 的时候,会发现上传成功后,缩略图会消失,变成一个 svg 图标,像下面这样:
上传完成后缩略图消失
而自动上传是可以做到上传后保留缩略图的。原因大概是因为手动上传对beforeUpload
return false
,使 Upload 组件无法再触发组件上的 onChange
事件,uploadList 组件上的 previewFile
无法再次触发,导致 fileList 更新时无属性存储缩略图,导致缩略图丢失:
// antd/libs/upload/UploadList.js
var previewFile = function previewFile(file, callback) {
var reader = new FileReader();
reader.onloadend = function () {
return callback(reader.result);
};
reader.readAsDataURL(file);
};
// previewFile 的调用
previewFile(file.originFileObj, function (previewDataUrl) {
file.thumbUrl = previewDataUrl;
_this2.forceUpdate();
});
可以发现,缩略图的显示方法是利用 FileReader
的readAsDataURL
将File对象
转为 base64,赋值给File对象
的thumbUrl
属性,组件读到这个属性作为<img`>
中src
的值从而显示缩略图。
那么,我们只要在代码中手动做一次文件的 base64 转换即可:
beforeUpload = (file) => {
const r = new FileReader();
r.readAsDataURL(file);
r.onload = e => {
file.thumbUrl = e.target.result;
this.setState(state => ({
fileList: [...state.fileList, file],
}));
};
return false;
}
将 base64 同样存储在 file 的 thumbUrl
属性中,就可以在文件上传成功后仍然显示缩略图。
手动上传文件后改变上传列表样式
自动上传在上传完成后,失败和成功都会有样式的改变,如:
文件上传失败
如果手动上传同样同样在失败成功后都没有样式上的改变。
要解决这个问题,还是要继续借鉴自动上传的经验,看看组件的源码。
翻看源码会发现,上传后的样式取决于file
的status
属性,组件会根据不同的值给文件不同的样式,如果 file.status
是 error
,则会应用error
相关的样式,如:
var infoUploadingClass = (0, _classnames2['default'])((_classNames = {},
(0, _defineProperty3['default'])(_classNames, prefixCls + '-list-item', true),
(0, _defineProperty3['default'])(_classNames, prefixCls + '-list-item-' + file.status, true),
_classNames
));
.ant-upload-list-picture-card .ant-upload-list-item-error,
.ant-upload-list-picture .ant-upload-list-item-error {
border-color: #f5222d
}
说实话第一段代码我看不太懂,两个括号连在一起,有懂的同学还望赐教。
总之,就是根据 file.status
去拼出一个类名来应用样式,这就好办了,只要在文件传输完成后,给 file.status
设一个值就好了。
在自动上传中,上传完成后组件会对 fileList
做处理,自动添加 file.status
属性,但是因为手动上传对beforeUpload
返回了false
,导致组件无法再对 fileList
进行操作,所以就要我们在业务代码里自己添加了。
手动上传显示进度
UploadList 组件中关于显示进度的代码在这里:
if (file.status === 'uploading') {
// show loading icon if upload progress listener is disabled
var loadingProgress = 'percent' in file ? React.createElement(_progress2['default'], (0, _extends3['default'])({
type: 'line'
}, _this3.props.progressAttr, {
percent: file.percent
})) : null;
progress = React.createElement(
'div', {
className: prefixCls + '-list-item-progress',
key: 'progress'
},
loadingProgress
);
}
读取file.percent
,根据percent
去控制样式,关于文件上传的进度,因为我使用的是 axios,所以在 axios 的 onUploadProgress
中去读取进度并修改 fileList 即可:
axios({
method: 'post',
url: `${action}/${uploadTypeNum}`,
data: e.target.result,
onUploadProgress: progressEvent => {
const complete = (progressEvent.loaded / progressEvent.total * 100 | 0);
file.percent = complete;
// this.ref 是上传组件
this.ref.onChange({ file, fileList: this.state.fileList, });
},
})
注意:以上对 file
添加属性值,并不需要每次都执行setState
,只要执行 Upload 组件的 onChange,将file, fileList
传入即可
2019.1.22 更新:
之前我使用了 this.ref.onChange
去改变 UploadList 的状态,后来发现,可以不手动改变 UploadList 的状态。方法就是将 state
里的 fileList
传入 Upload
组件中:
render() {
const { fileList, } = this.state;
return (
<Upload fileList={fileList} />
)
}
文件状态发生改变后改变 fileList
即可:
fileList.forEach((file) => {
const r = new FileReader();
r.readAsArrayBuffer(file);
r.onload = e => {
file.status = 'uploading';
this.setState({
fileList,
});
axios({
method: 'post',
url: `${action}/${uploadTypeNum}`,
data: e.target.result,
onUploadProgress: progressEvent => {
const complete = (progressEvent.loaded / progressEvent.total * 100 | 0);
file.percent = complete;
this.setState({
fileList,
});
},
})
.then(res => {
if (res.status === 200 && res.data.state === 'success') {
file.status = 'success';
file.code = res.data.code;
this.setState((state) => ({
uploading: false,
}));
this.setState({
fileList,
});
} else {
this.setState({
uploading: false,
});
file.status = 'error';
this.setState({
fileList,
});
message.error(`${file.name}上传失败`);
}
})
.catch(() => {
this.setState({
uploading: false,
});
message.error(`${file.name}上传失败了`);
file.status = 'error';
this.setState({
fileList,
});
});
};
});
参考文章:
ant design Upload组件的使用总结。 - 知乎
Upload manually cann't trigger Upload's onChange / 手动上传无法触发 Upload 组件的 onChange 事件 -- github issue
网友评论