antd上傳組件踩坑和封裝

效果圖:

1、公共組件封裝:

將antd中的上傳組件進行改進:

不同文件格式使用不同上傳樣式;

增加上傳限制:大小,數量,尺寸;

UploadCustom.js

import { PlusOutlined, UploadOutlined } from '@ant-design/icons';
import { Button, message, Modal, Upload } from 'antd';
import Axios from 'axios';
import bytes from 'bytes';
import dayjs from 'dayjs';
import React, { memo, useEffect, useState } from 'react';
import { getRandomIntInclusive } from '../../utils/utils';

function UploadOSS(props) {
  const {
    onChange,
    value,
    dirPath,
    listType,
    multiple,
    accept,
    limit,
    sizeLimit,
    className,
    width,
    height,
  } = props;
  const [uploadData, setUploadData] = useState({});
  let flag = false;

  // 初始化上傳所需參數(從接口獲取,過程省略)
  const init = async () => {
    setUploadData({});
  };

  useEffect(() => {
    init();
  }, [dirPath]);

  // 捕捉上傳出錯的文件
  const handleChange = ({ file, fileList }) => {
    if (file.status === 'error') {
      message.error('上傳出錯!');
    }
    if (onChange) {
      onChange(fileList.filter((v) => v.status === 'done' || v.status === 'uploading'));
    }
  };

  // 移除文件
  const onRemove = (file) => {
    const files = value.filter((v) => v.url !== file.url);
    if (onChange) {
      onChange(files);
    }
  };

  // 上傳之前轉換對象
  const transformFile = (file) => {
    const suffix = file.name.slice(file.name.lastIndexOf('.'));
    const filename = `${getRandomIntInclusive(1000, 9999)}-${dayjs().format(
      'YYYY-MM-DD',
    )}${Date.now()}${suffix}`;
    file.url = `${dirPath}${filename}`;
    return file;
  };

  // 上傳所需額外參數
  const getExtraData = (file) => {
    return {
      key: file.url,
      success_action_status: 200,
      policy: uploadData.policy,
      Signature: uploadData.signature,
    };
  };

  // 圖片尺寸比例限制
  const checkSize = (file) => {
    return new Promise((resolve, reject) => {
      const url = window.URL || window.webkitURL;
      const img = new Image();
      img.onload = () => {
        const valid =
          img.width >= width && img.height >= height && img.width / img.height === width / height;
        valid ? resolve() : reject();
      };
      img.src = url.createObjectURL(file);
    }).then(
      () => {
        return true;
      },
      () => {
        if (flag) {
          Modal.error({
            title: `圖片尺寸不符合要求,請修改後重新上傳!`,
          });
          flag = false;
        }
        return Promise.reject();
      },
    );
  };

  // 圖片大小限制
  const checkLimit = (file) => {
    return new Promise((resolve, reject) => {
      file.size <= sizeLimit ? resolve() : reject();
    }).then(
      () => {
        return true;
      },
      () => {
        if (flag) {
          Modal.error({
            title: `超過大小限制${bytes(sizeLimit)},請重新選擇!`,
          });
          flag = false;
        }
        return Promise.reject();
      },
    );
  };

  // 數量限制
  const checkLen = (fileList) => {
    return new Promise((resolve, reject) => {
      const isLen = value.length + fileList.length;
      isLen <= limit ? resolve() : reject();
    }).then(
      () => {
        return true;
      },
      () => {
        if (flag) {
          Modal.error({
            title: `超過最大上傳數量${limit}張,請重新選擇!`,
          });
          flag = false;
        }
        return Promise.reject();
      },
    );
  };

  // 判斷所有條件滿足才能上傳
  const beforeUpload = async (file, fileList) => {
    flag = true;
    const isLen = limit ? await checkLen(fileList) : true;
    const isSizeLimit = sizeLimit ? await checkLimit(file) : true;
    const isSize = width ? await checkSize(file) : true;
    const expire = uploadData.expire * 1000;
    if (expire < Date.now()) {
      await init();
    }
    return isLen && isSizeLimit && isSize;
  };

  // 圖片預覽處理
  const handlePreview = async (file) => {
    let src = file.url;
    if (!src || src.indexOf('http') === -1) {
      src = await new Promise((resolve) => {
        const reader = new FileReader();
        reader.readAsDataURL(file.originFileObj);
        reader.onload = () => resolve(reader.result);
      });
    }
    const image = new Image();
    image.src = src;
    const imgWindow = window.open(src);
    imgWindow.document.write(image.outerHTML);
  };

  const uploadProps = {
    name: 'file',
    fileList: value,
    action: uploadData.host,
    onChange: handleChange,
    data: getExtraData,
    onPreview: handlePreview,
    onRemove,
    transformFile,
    beforeUpload,
    listType,
    multiple,
    accept,
    className,
  };

  // 文件和圖片使用不同的樣式
  const Con = () =>
    listType ? (
      <div>
        <PlusOutlined />
        <div className="ant-upload-text">上傳</div>
      </div>
    ) : (
      <Button>
        <UploadOutlined /> 上傳
      </Button>
    );

  return <Upload {...uploadProps}>{value && value.length < limit && Con()}</Upload>;
}

export default memo(UploadCustom);

使用組件:

index.js

import UploadCustom from '';


return (
  <>
    <UploadCustom
        dirPath="files/"
        limit={1}
        sizeLimit={bytes('2GB')}
        accept=".exe,.msi,.rar,.zip,.7z"
    ></UploadCustom>

    <UploadCustom
        dirPath="appstore/adp/logo/"
        listType="picture-card"
        accept="image/*"
        limit={1}
        sizeLimit={bytes('5MB')}
        className="upload-list-inline"
        width={256}
        height={256}
     ></UploadCustom>
  </>
)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章