react-dropzone:在拖动时检查文件处于活动状态

IT技术 reactjs react-dropzone
2021-05-26 15:10:31

我已经使用react-dropzone.

我想检查文件,用户dragges到悬浮窗,并做到这一点,而他们正在拖(之前他们被丢弃到悬浮窗)。

我试过这个:

<Dropzone
  accept="application/pdf"
  onDrop={this.handleDragDrop}
>
  {({ draggedFiles, isDragActive, isDragReject, acceptedFiles, rejectedFiles }) => {
    if (isDragActive) {
      ... inspect files here (before dropping)
    }
  }}
</Dropzone>

但非draggedFiles,acceptedFilesrejectedFiles有任何value。

我在这里遗漏了什么......?


编辑:

为了让我的问题更清楚:

我想对文件进行验证,然后用户将它们放到dragzone. 通过将 mimetypes 传递给accept属性的验证在我的场景中是不够的:

  1. 用户将文件拖到 上dragzone并被onDragOver触发
  2. 现在检查文件并dragzone更新以显示消息files are okfiles not ok,因此用户删除文件之前获取此信息
  3. 用户正在删除文件并被onDrop触发
4个回答

简答

AFAIK 你不能

长答案

让我们看看下面的代码:

<Dropzone 
  accept="image/*,application/pdf" 
  maxSize={5000000}
  onDrop={this.onDrop}
  onDragEnter={this.onDragEnter}
>
  {({getRootProps, getInputProps, isDragAccept, isDragReject }) => {
    let classes = 'form-control'
    let placeholder = <p>Drag files here</p>;
    if (isDragAccept) {
      classes = `${classes} border-success bg-light`;
      placeholder = <p className="text-success">Drop files now</p>;
    } 
    if (isDragReject) {
      classes = `${classes} border-danger bg-light`;
      placeholder = <p className="text-danger">Some files are not allowed</p>
    }
    return (
      <div {...getRootProps()} style={{ height: '100px' }} className={classes}>
        <input {...getInputProps()} />
        {placeholder}
      </div>
    );
  }}
</Dropzone>

如果要删除的文件满足某些要求(任何图像类型或 pdf 文件且大小小于 5MB),则此代码段会更改放置区的样式。如果我们将任何文件拖到放置区上,则acceptedFiles的值rejectedFiles都是一个空数组。的值draggedFiles是一个DataTransferItems数组,它为我们提供了被拖动文件kindtype,例如{kind: "file", type: "application/pdf"}

此时,isDragAccept的值isDragReject是根据文件类型设置的因此,如果我们拖动图像或 pdf 文件,该值isDragAccept设置为true,文本Drop files now将显示在放置区中,其边框将根据类着色border-success但是如果文件大于 5MB 也会出现同样的情况!为什么?这是因为我们无法在 drop 事件之前读取文件。

让我们看看事件处理程序:

onDrop = (acceptedFiles, rejectedFiles, event) => {
  console.log(event.dataTransfer.items)
  console.log(event.dataTransfer.files)
}

onDragEnter = (event) => {
  console.log(event.dataTransfer.items)
  console.log(event.dataTransfer.files)
}

拖动事件为我们提供了一个dataTransfer属性,它是一个DataTransfer对象。这里有两个对我们很重要的属性:

  • DataTransfer.items

    这是一个DataTransferItemList对象,它为我们提供了一个DataTransferItems列表它是draggedFiles数组中的同一个对象,我们可以在两个处理程序中访问它:onDragEnter 和 onDrop。

  • DataTransfer.files

    这保存了拖动操作FileList对象,但它在拖动事件中为空,因此我们只能在拖放后访问它。例如,在前面的代码中,如果我们拖放某个文件,我们会为显示的事件的控制台日志获得以下输出:

FileList {length: 0} // dragEnter event
FileList {0: File(30299626), length: 1} // drop event

如果我们在 drop 之后访问 File 列表的元素 0,我们将得到:

File(30299626) {name: "python_101.pdf", lastModified: 1549327543709, lastModifiedDate: Mon Feb 04 2019 21:45:43 GMT-0300 (Chile Summer Time), webkitRelativePath: "", size: 30299626, …}

因此,我们只能在 drop 事件之后访问文件的数据

这样做(react):

  onDragOverHandle(event) {
    event.stopPropagation();
    event.preventDefault();
    console.log(event.dataTransfer.items[0])
  }

您可以获得拖动目标类型,例如:

{kind: "file", type: "image/png"} 或者 {kind: "file", type: "video/mp4"}

然后你就可以做你想做的事情了。

希望能帮到你~

正如@Jay lu sayied,你可以使用这样的东西:

const onDragEnter = (event) => {
    const fileType = event.dataTransfer.items[0].type;
    const validTypes = ['image/png', 'image/jpeg', 'image/jpg'];
    const valitate = validTypes.some(types => types === fileType);
    !valitate && setDanger(true);
  }

const onDragLeave = (event) => {
    setDanger(false);
  }

<Dropzone
        onDrop={ onDrop }
        accept='image/jpeg, image/png, image/jpg'
        maxSize={500000}
        onDragEnter={onDragEnter}
        onDragLeave={onDragLeave}
      >

您需要使用 : 初始化您的状态this.state = { files: [] }并在函数中处理放置文件:onDrop(files) { // do stuff with files... }

这是文档https://react-dropzone.js.org/的示例摘录

class Basic extends React.Component {
  constructor() {
    super()
    this.state = { files: [] }
 }

 onDrop(files) {
   this.setState({
     files
   });
 }

 render() {
   return (
     <section>
    <div className="dropzone">
      <Dropzone onDrop={this.onDrop.bind(this)}>
        <p>Try dropping some files here, or click to select files to upload.</p>
      </Dropzone>
    </div>
    <aside>
      <h2>Dropped files</h2>
      <ul>
        {
          this.state.files.map(f => <li key={f.name}>{f.name} - {f.size} bytes</li>)
        }
      </ul>
    </aside>
  </section>
);
}}