限制 react-dropzone 中的图像尺寸

restrict image dimension in react-dropzone

我正在使用 react-dropzone 上传图片。一切正常。图像大小的验证也工作正常。但我无法检查图像的尺寸。我想验证图像的宽度和高度以强制用户上传介于指定宽度和高度之间的图像。我试过 image.addEventListener('load') 但这不起作用。

这是我所做的

export const UploadField = ({ preview, label, uploadProps, ...props }) => {
  const {
    input: { onChange },
    disabled
  } = props;

  const {
    isDragActive,
    getRootProps,
    getInputProps,
    isDragReject,
    rejectedFiles
  } = useDropzone({
    onDrop: files => {
      onChange(
        files.map(file => {
          const image = new Image();
          image.addEventListener("load", () => {
            console.log("image", image);
          });
          return Object.assign(file, {
            preview: URL.createObjectURL(file)
          });
        })
      );
    },
    ...uploadProps
  });

  const isFileTooLarge =
    rejectedFiles.length > 0 && rejectedFiles[0].size > uploadProps.maxSize;

  const files = props.input.value;

  if (disabled) {
    return null;
  }

  return (
    <>
      {label && <Label>{label}</Label>}
      <DropzoneContainer {...getRootProps()}>
        <input {...getInputProps()} />
        {!isDragActive && "Click here or drop a file to upload!"}
        {isDragActive && !isDragReject && "Drop it like it's hot!"}
        {isDragReject && "File type not accepted, sorry!"}
        {isFileTooLarge && (
          <div className="text-danger mt-2">File is too large.</div>
        )}
      </DropzoneContainer>
      <div>
        {files && files !== undefined ? (
          <>
            <Preview files={files} isLocal />
          </>
        ) : (
          <Preview files={preview} isLocal={false} />
        )}
      </div>
    </>
  );
};

export default UploadField;

UploadField.defaultProps = {
  uploadProps: {
    accept: "image/*",
    multiple: false,
    minSize: 0,
    maxSize: 5242880
  }
};

const DropzoneContainer = styled.div`
  width: 100%;
  padding: 14px;
  border-width: 2px;
  border-radius: 2px;
  border-color: ${props => getColor(props)};
  border-style: dashed;
  background-color: #fafafa;
  color: #bdbdbd;
  outline: none;
  transition: border 0.24s ease-in-out;
`;

const getColor = props => {
  if (props.isDragAccept) {
    return "#00e676";
  }
  if (props.isDragReject) {
    return "#ff1744";
  }
  if (props.isDragActive) {
    return "#2196f3";
  }
  return "#eeeeee";
};

您永远不会为图像设置 src,因此您的事件处理程序永远不会触发。尝试设置 image.src = URL.createObjectURL(file)。文件加载后,您的 'load' 处理程序将触发。

尝试更改 onDrop 回调的内容以包含以下内容:

const filteredImages = [];
let counter = 0;

files.map(file => {
    const image = new Image();
    image.addEventListener('load', () => {
        console.log(`${image.width}x${image.height}`)

        // only select images within width/height limits
        if (image.width < WIDTH_LIM && image.height < HEIGHT_LIM) {
            filteredImages.push(image)
        }

        // increment counter for each image we go through
        counter += 1;

        // if we have gone through all the files, handle the ones that
        // made it through the filter using `handleImages` function
        if (counter === files.length) handleImages(filteredImages);
    });
    image.src = URL.createObjectURL(file)
})

如果您想在 onDrop 之前验证尺寸,您可以使用 getFilesFromEventvalidator 回调,如下所示。

优点 对于诸如 maxSize 和 accept 之类的错误,您可以从 rejectedFiles.

中获取卡在维度验证中的文件

缺点 如果您使用的是打字稿,则必须消除任何类型的类型错误。

const {
    isDragActive,
    getRootProps,
    getInputProps,
    isDragReject,
    rejectedFiles
  } = useDropzone({
    getFilesFromEvent: async (event) => {
      const files = event.target.files || event.dataTransfer.files
      const promises = []
      for (let index = 0; index < files.length; index++) {
        const file = files[index]
        const promise = new Promise((resolve, reject) => {
          const image = new Image()
          let url: string
          image.onload = function () {
            file.width = image.width
            file.height = image.height
            resolve(file)
          }
          url = URL.createObjectURL(file)
          image.src = url
        })
        promises.push(promise)
      }
      return await Promise.all(promises)
    },
    validator: (file) => {
      // You can access width/height properties
      if(file.width < MIN_WIDTH) {
        return {
          code: "small-width",
          message: `Image width must be greater than ${MIN_WIDTH}`,
        }
      }
      return null
    }

  });