最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - restrict image dimension in react-dropzone - Stack Overflow

programmeradmin7浏览0评论

I am using react-dropzone for image upload. Everything is working fine. Validation for image size is also working fine. But I could not check the dimension for image. I want to validate the image's width and height to enforce user to upload the image in between those specified width and height. I tried image.addEventListener('load') but this is not working.

Here is what I have done

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";
};

I am using react-dropzone for image upload. Everything is working fine. Validation for image size is also working fine. But I could not check the dimension for image. I want to validate the image's width and height to enforce user to upload the image in between those specified width and height. I tried image.addEventListener('load') but this is not working.

Here is what I have done

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";
};
Share Improve this question asked Jan 16, 2020 at 1:41 SerenitySerenity 4,0548 gold badges49 silver badges96 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 10

You never set the src for the image so your event handler never fires. Try setting image.src = URL.createObjectURL(file). Once the file loads, your 'load' handler will fire.

Try changing the contents of your onDrop callback to include this:

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)
})

If you want to validate dimensions before onDrop, you can use getFilesFromEvent and validator callbacks like below.

Pros As with errors such as maxSize and accept, you can get files that are stuck in validation for dimention from rejectedFiles.

Cons f you are using typescript, you have to eliminate the type error with any type.

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
    }

  });



发布评论

评论列表(0)

  1. 暂无评论