有什么好方法可以将react-image-crop与react-dropzone连接起来吗?

发布时间:2020-07-07 17:46

我一直在尝试将react-image-crop与react dropzone连接起来,但这似乎不起作用,或者我做错了什么。

那是我的拖放组件

 import { useDropzone } from 'react-dropzone';
import React, { useMemo, useCallback, useEffect, useRef } from 'react';

import styles from './index.module.scss';
import { FormField, FormCheckbox, Button } from 'components/common';
import toastr from 'utils/toastr';
import ModalInfoCrop from '../../../ModalnfoCrop';

const DragAndDrop = ({ value, onChange, field, form }) => {
  const uploadInputRef = useRef(null);

  useEffect(
    () => () => {
      files.forEach((file) => URL.revokeObjectURL(file.preview));
    },
    [files]
  );

  const files = useMemo(() => {
    return (field && field.value) || value || [];
  }, [field, value]);

  const onFileAdd = useCallback(
    (files) => {
      if (field && form) {
        form.setFieldValue(field.name, files);
      } else {
        onChange && onChange(files);
      }
    },
    [field, form, onChange]
  );
  const error = useMemo(() => !!(field && form && form.errors[field.name]), [
    field,
    form,
  ]);

  const { getRootProps, getInputProps } = useDropzone({
    accept: 'image/*',
    onDrop: (acceptedFiles) => {
      let files_arr = files;
      if (files.length) {
        acceptedFiles.forEach((element) => {
          if (element.size <= 15728640) {
            let isRepeated = false;
            files.forEach((file) => {
              if (file.name === element.name) {
                isRepeated = true;
                return;
              }
            });
            if (!isRepeated) {
              files_arr.push(element);
            }
          } else {
            toastr.error(`File ${element.name} is more than MB`);
          }
        });
      } else {
        files_arr = acceptedFiles;
      }
      onFileAdd(
        files_arr.map((file) =>
          Object.assign(file, {
            preview: URL.createObjectURL(file),
          })
        )
      );
    },
  });

  const changeMainPhoto = (e) => {
    e.preventDefault();
    let mainImageIndex = +e.target.getAttribute('data-fileindex');
    form.setFieldValue('mainPhotoIndex', mainImageIndex);
  };

  const deletePhoto = (deletedIndex) => {
    files.splice(deletedIndex, 1);

    if (deletedIndex === form.values.mainPhotoIndex)
      form.setFieldValue('mainPhotoIndex', 0);

    onFileAdd(
      files.map((file) =>
        Object.assign(file, {
          preview: URL.createObjectURL(file),
        })
      )
    );
  };

  const thumbs = files.map((file, index) => (
    <div className={styles.thumb} key={index}>
      <div className={styles.thumbInner}>
        <img
          src={(file && file.preview) || file}
          className={styles.imgInner}
          alt="item_photo"
        />
        <FormCheckbox
          value={form.values.mainPhotoIndex === index}
          onClick={changeMainPhoto}
          inputProps={{ 'data-fileindex': index }}
          className={styles.mainImageCheckBox}
          name=""
        />
        <Button
          onClick={() => deletePhoto(index)}
          color="secondary"
          className={styles.imageDeleteButton}
        >
          X
        </Button>
      </div>
    </div>
  ));

  return (
    <>
      <section className={error ? styles.wrapper_error : styles.wrapper}>
        <div
          {...getRootProps({ className: 'dropzone' })}
          style={{
            margin: '.5rem 1rem',
          }}
        >
          <input
            name="photos"
            ref={uploadInputRef}
            type="file"
            {...getInputProps()}
          />
          <p
            style={{
              margin: '.5rem auto',
              fontWeight: '600',
            }}
          >
            Drag Photos here <br /> or
          </p>
          <div
            style={{
              backgroundColor: 'black',
              padding: '.5rem 1rem',
              color: 'white',
              borderRadius: '40px',
              margin: '.5rem 30%',
            }}
          >
            + Add Photos
          </div>
        </div>
      </section>
      <aside className={styles.thumbsContainer}>{thumbs}</aside>
    </>
  );
};

export default ({ name, ...props }) =>
  name ? (
    <FormField name={name} component={DragAndDrop} {...props} />
  ) : (
    <DragAndDrop {...props} />
  );

这就是react-image-crop所在的位置,我尝试了多种方法在上传照片时打开农作物,但是还没有找到一个好的解决方案,因此删除了所有内容,这就是我现在所在的位置

import React, { Component, useState, useRef, useEffect, useCallback } from 'react';
import ReactCrop, { makeAspectCrop } from 'react-image-crop';
import { Button, Dialog, MuiThemeProvider } from '@material-ui/core';
import styles from './index.module.scss';
import { parseWithOptions } from 'date-fns/fp';

const pixelRatio = 4;

function getResizedCanvas(canvas, newWidth, newHeight) {
  const tmpCanvas = document.createElement("canvas");
  tmpCanvas.width = newWidth;
  tmpCanvas.height = newHeight;

  const ctx = tmpCanvas.getContext("2d");
  ctx.drawImage(
    canvas,
    0,
    0,
    canvas.width,
    canvas.height,
    0,
    0,
    newWidth,
    newHeight
  );

  return tmpCanvas;
}

function generateDownload(previewCanvas, crop) {
  if (!crop || !previewCanvas) {
    return;
  }

  const canvas = getResizedCanvas(previewCanvas, crop.width, crop.height);

  canvas.toBlob(
    blob => {
      const previewUrl = window.URL.createObjectURL(blob);

      const anchor = document.createElement("a");
      anchor.download = "cropPreview.png";
      anchor.href = URL.createObjectURL(blob);
      anchor.click();

      window.URL.revokeObjectURL(previewUrl);
    },
    "image/png",
    1
  );
}

export default function ModalInfoCrop(photo) {
  const [upImg, setUpImg] = useState(photo);
  const imgRef = useRef(photo);
  const previewCanvasRef = useRef(null);
  const [crop, setCrop] = useState({ unit: "%", width: 30, aspect: 16 / 9 });
  const [completedCrop, setCompletedCrop] = useState(null);

  const onSelectFile = e => {
    if (e.target.files && e.target.files.length > 0) {
      const reader = new FileReader();
      reader.addEventListener("load", () => setUpImg(reader.result));
      reader.readAsDataURL(e.target.files[0]);
    }
  };

  const onLoad = useCallback(img => {
    imgRef.current = img;
  }, []);

  useEffect(() => {
    if (!completedCrop || !previewCanvasRef.current || !imgRef.current) {
      return;
    }

    const image = imgRef.current;
    const canvas = previewCanvasRef.current;
    const crop = completedCrop;

    const scaleX = image.naturalWidth / image.width;
    const scaleY = image.naturalHeight / image.height;
    const ctx = canvas.getContext("2d");

    canvas.width = crop.width * pixelRatio;
    canvas.height = crop.height * pixelRatio;

    ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
    ctx.imageSmoothingEnabled = false;

    ctx.drawImage(
      image,
      crop.x * scaleX,
      crop.y * scaleY,
      crop.width * scaleX,
      crop.height * scaleY,
      0,
      0,
      crop.width,
      crop.height
    );
  }, [completedCrop]);

  return (
    <div className="App">
      <div>
        <input type="file" accept="image/*" onChange={onSelectFile} />
      </div>
      <ReactCrop
        src={upImg}
        onImageLoaded={onLoad}
        crop={crop}
        onChange={c => setCrop(c)}
        onComplete={c => setCompletedCrop(c)}
      />
    </div>
  );
}

我只是不知道如何正确地实施此方法,因此,我感谢每一个建议,在此先感谢

回答1
react-image-crop 相关推荐