前端技术选型: React Hook + typescript
antd版本:3.18
import {Button, Form, Input, Modal, Upload, Icon} from 'antd';
const RegistrationForm = (props: IProps) => {
const {
form: { getFieldDecorator , validateFields},
previewData
} = props;
const [filesList, setFilesList] = useState<UploadFile[]>([]);
const [previewImage, setPreviewImage] = useState('');
const [previewVisible, setPreviewVisible] = useState(false);
const normFile = (e: any) => {
if (Array.isArray(e)) {
return e;
}
return e && e.fileList;
};
// 限制图片的格式,size,分辨率
const handleBeforeUpload = (file: RcFile, FileList: RcFile[]): boolean | PromiseLike<void> => {
const isJPG = file.type === 'image/jpeg';
const isJPEG = file.type === 'image/jpeg';
const isGIF = file.type === 'image/gif';
const isPNG = file.type === 'image/png';
if (!(isJPG || isJPEG || isGIF || isPNG)) {
Modal.error({
title: '只能上传JPG 、JPEG 、GIF、 PNG格式的图片~'
});
return false;
}
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isLt2M) {
Modal.error({
title: '超过2M限制,不允许上传~'
});
return false;
}
return (isJPG || isJPEG || isGIF || isPNG) && isLt2M && checkImageWH(file);
};
// 返回一个promise:通过检测则返回reslove;失败则返回reject,并阻止图片上传
const checkImageWH = (file: RcFile): PromiseLike<void> => {
const value: IFileProps = file;
return new Promise((resolve, reject) => {
const filereader = new FileReader();
filereader.onload = (e: any) => {
const src = e.target.result;
const image = new Image();
image.onload = () => {
value.width = image.width;
value.height = image.height;
resolve();
};
image.onerror = reject;
image.src = src;
};
filereader.readAsDataURL(value);
});
};
const handleChange = (info: UploadChangeParam) => {
console.log(info.fileList);
console.log(info.file);
setFilesList(info.fileList);
};
const handleCancel = () => {
setPreviewVisible(false);
};
const handlePreview = (file: UploadFile) => {
const imageUrl = file.url || file.thumbUrl || '';
setPreviewImage(imageUrl);
setPreviewVisible(true);
};
return (
<div>
<Form>
<FormItem label="截图" {...formItemLayout}>
{getFieldDecorator('upload',
{ valuePropName: 'fileList',
getValueFromEvent: normFile
}
)(
<Upload
action="/api/image/upload/"
data={file => ({
image_file: file
})}
listType="picture-card"
fileList={filesList}
onPreview={handlePreview}
beforeUpload={handleBeforeUpload}
onChange={handleChange}
>
{
filesList.length >= 6 ? null : <Button>
<Icon type="upload"/> Click to upload
</Button>
}
</Upload>
)}
</FormItem>
<Modal visible={previewVisible} footer={null} onCancel={handleCancel}>
<img alt="example" style={{ width: '100%' }} src={previewImage} />
</Modal>
</Form>
</div>);
};
const ProductForms = Form.create<IProps>()(RegistrationForm);
export default ProductForms;
依据上方的代码,通过 Antd 的 upload 组件将图片上传成功后,点击图片的缩略图,理应可以在当前页面弹出 Modal,预览图片。但实际的结果是,浏览器可能会卡死。
定位问题发现,原因是:图片上传成功后, upload 会将其转为 base64编码。base64这个字符串太大了,点击图片预览的时候,浏览器在解析一大串字符串,然后就卡死了。详细过程描述如下。
上方代码中,我们可以把 handleChange(file, fileList)方法中的 file、以及 fileList打印出来看看。 file指的是当前正在上传的 单个 img,fileList是已上传的全部 img 列表。 当我上传完 两张图片后, 打印结果如下:
file的打印的结果如下:
{
"uid": "rc-upload-1551084269812-5",
"width": 600,
"height": 354,
"lastModified": 1546701318000,
"lastModifiedDate": "2019-01-05T15:15:18.000Z",
"name": "e30e7b9680634b2c888c8bb513cc595d.jpg",
"size": 31731,
"type": "image/jpeg",
"percent": 100,
"originFileObj": {
"uid": "rc-upload-1551084269812-5",
"width": 600,
"height": 354
},
"status": "done",
"thumbUrl": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAHQ9qKKlbimcXrIH9o2vH/AC2T+ddPj98v+9RRWsuhnHdk0ar9qb5R0Pb6VPB/qh9aKKiRr0Irnt/vUDr+NFFJCRqWxJik5Pb+dLJ938aKK06mYSdKKKKBH//Z",
"response": {
"retCode": 0,
"imgUrl": "http://qianguyihao.com/opfewfwj098902kpkpkkj976fe.jpg",
"photoid": 271850
}
}
fileList 的打印结果:
[
{
"uid": "rc-upload-1551084269812-3",
"width": 1000,
"height": 667,
"lastModified": 1501414799000,
"lastModifiedDate": "2017-07-30T11:39:59.000Z",
"name": "29381f30e924b89914e91b33.jpg",
"size": 135204,
"type": "image/jpeg",
"percent": 100,
"originFileObj": {
"uid": "rc-upload-1551084269812-3",
"width": 1000,
"height": 667
},
"status": "done",
"thumbUrl": "data:image/jpeg;base64,/E3ju1tlaK1fzJOnHQU3LsLV7HO6Zrk11MZJ7luT0A4FZuRagi9quvzQQ4iuEJ7ZpqTG4djDsPFl2Lg733f8C4q+YhQ8zoYfGSqoMmfwo5huLL0HjiyPDSYPvxRdC1XQvxeLrB8fvl/OnoLmL9vrdvvYS3NGFVe2YsASOh71JfQyrqV2mXLHOcccVSIYEnDyZO9XXB9KYH//Z",
"response": {
"retCode": 0,
"msg": "success",
"imgUrl": "http://qianguyihao.com/hfwpjouiurewnmbhepr689.jpg",
}
},
{
"uid": "rc-upload-1551084269812-5",
"width": 600,
"height": 354,
"lastModified": 1546701318000,
"lastModifiedDate": "2019-01-05T15:15:18.000Z",
"name": "e30e7b9680634b2c888c8bb513cc595d.jpg",
"size": 31731,
"type": "image/jpeg",
"percent": 100,
"originFileObj": {
"uid": "rc-upload-1551084269812-5",
"width": 600,
"height": 354
},
"status": "done",
"thumbUrl": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAHQ9qKKlbimcXrIH9o2vH/AC2T+ddPj98v+9RRWsuhnHdk0ar9qb5R0Pb6VPB/qh9aKKiRr0Irnt/vUDr+NFFJCRqWxJik5Pb+dLJ938aKK06mYSdKKKKBH//Z",
"response": {
"retCode": 0,
"imgUrl": "http://qianguyihao.com/opfewfwj098902kpkpkkj976fe.jpg",
"photoid": 271850
}
}
]
上方的json数据中,需要做的几点解释:
这个base64编码非常非常长。当点击图片预览的时候,其实就是加载的 thumbUrl 这个字段里的资源,难怪浏览器会卡死。
解决办法:在 handleChange方法里,图片上传成功后,将 thumbUrl 字段里面的 base64 编码改为真实的图片url。代码实现如下:
handleChange = ({ file, fileList }) => {
console.log(JSON.stringify(file)); // file 是当前正在上传的 单个 img
console.log(JSON.stringify(fileList)); // fileList 是已上传的全部 img 列表
// 【重要】将 图片的base64替换为图片的url。 这一行一定不会能少。
// 图片上传成功后,fileList数组中的 thumbUrl 中保存的是图片的base64字符串,这种情况,导致的问题是:图片上传成功后,点击图片缩略图,浏览器会会卡死。而下面这行代码,可以解决该bug。
fileList.forEach(imgItem => {
if (imgItem && imgItem.status == 'done' && imgItem.response && imgItem.response.imgUrl) {
imgItem.thumbUrl = imgItem.response.imgUrl;
}
});
setFilesList(ifilList);
};