AntDesign Upload組件上傳圖片

技術選型

前端技術選型: React Hook + typescript
antd版本:3.18

使用Upload上傳圖片

上傳效果截圖

在這裏插入圖片描述

預覽效果截圖

在這裏插入圖片描述
項目中完整寫法:

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數據中,需要做的幾點解釋:

  1. response字段裏面的數據,請求後端接口後,後臺返回給前端數據,包含了圖片中的url鏈接
  2. status字段裏存放的是圖片上傳的實時狀態,包括上傳中、上傳完成、上傳失敗。
  3. thumbUrl字段裏面存放的是圖片的base64編碼。

這個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);
  };
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章