如何使用 react-dropzone 在 React 中创建拖放文件上传功能

介绍

react-dropzone是一个符合 HTML5 的 React 组件,用于处理文件的拖放和丢弃。

HTML5 支持使用 <input type="file" />的文件上传。 react-dropzone 为您提供额外的功能,如定制 dropzone、显示预览、限制文件类型和数量。

<$>[注] 注: 如果您正在使用Vue而不是React,请参阅我们的教程 vue-dropzone

在本教程中,您将了解如何在您的 React 项目中添加react-dropzone,并探索它提供的一些功能。

前提条件

要完成本教程,您将需要:

本教程已通过 Node v15.3.0、npm v7.4.0、react v17.0.1 和 react-dropzone v11.2.4 进行验证。

步骤1 - 设置项目

开始使用 create-react-app来生成 React App,然后安装依赖:

1npx create-react-app react-dropzone-example

更改到新项目目录:

1cd react-dropzone-example

点击安装react-dropzone:

1npm install [email protected]

在此时刻,你有一个新的React项目,具有react-dropzone

步骤 2 – 添加 Dropzone 组件

「react-dropzone」具有默认设置,允许您以最小的配置添加它。

至少,您需要一个onDrop属性,可以处理丢失的文件和一些呼叫行动文本,以帮助限制用户的混乱:

 1[label src/DropzoneComponent.js]
 2import React, { useCallback } from 'react';
 3import { useDropzone } from 'react-dropzone';
 4
 5function DropzoneComponent() {
 6  const onDrop = useCallback(acceptedFiles => {
 7    console.log(acceptedFiles);
 8  }, []);
 9
10  const {
11    getRootProps,
12    getInputProps
13  } = useDropzone({
14    onDrop
15  });
16
17  return (
18    <div {...getRootProps()}>
19      <input {...getInputProps()} />
20      <div>Drag and drop your images here.</div>
21    </div>
22  )
23}
24
25export default DropzoneComponent;

此代码为您的应用程序提供拖放功能。

<$>[注] 注: 值得注意的是,尽管反应滴区旨在拖放文件,但它默认地接受点击事件到滴区,这将启动文件选择对话

将组件添加到您的 React 应用程序:

 1[label src/App.js]
 2import DropzoneComponent from './DropzoneComponent';
 3
 4function App() {
 5  return (
 6    <div className="App">
 7      <DropzoneComponent />
 8    </div>
 9  );
10}
11
12export default App;

运行你的应用程序,并在网页浏览器中观察它. 你应该看到一个潜水员,上面写着:`把你的图像拖到这里。

尝试将各种文件拖放到 React Dropzone 组件中。 代码目前使用console.log来显示文件. 上传文件的信息包括名称,最后修改,大小类型

在此时,您有一个工作 React Dropzone 组件,具有默认配置. 《react-dropzone》文档 额外的配置选项

步骤 3 – 设计 Dropzone 组件

默认情况下,react-dropzone 将没有风格. 该文档提供了常见外观的风格,该文档使用 flexbox 和 dashed 边界的组合,向用户表示可拖放文件的区域。

「react-dropzone」还支持在组件与(「isDragActive」)、接受文件(「isDragAccept」)、或拒绝文件(「isDragReject」)时的支持。

在应用于 JPEG 和 PNG 图像文件类型时,修改您的DropzoneComponent并使用isDragActive,isDragAcceptisDragReject:

 1[label src/DropzoneComponent.js]
 2import React, { useCallback, useMemo } from 'react';
 3import { useDropzone } from 'react-dropzone';
 4
 5const baseStyle = {
 6  display: 'flex',
 7  flexDirection: 'column',
 8  alignItems: 'center',
 9  padding: '20px',
10  borderWidth: 2,
11  borderRadius: 2,
12  borderColor: '#eeeeee',
13  borderStyle: 'dashed',
14  backgroundColor: '#fafafa',
15  color: '#bdbdbd',
16  transition: 'border .3s ease-in-out'
17};
18
19const activeStyle = {
20  borderColor: '#2196f3'
21};
22
23const acceptStyle = {
24  borderColor: '#00e676'
25};
26
27const rejectStyle = {
28  borderColor: '#ff1744'
29};
30
31function DropzoneComponent(props) {
32  const onDrop = useCallback(acceptedFiles => {
33    console.log(acceptedFiles);
34  }, []);
35
36  const {
37    getRootProps,
38    getInputProps,
39    isDragActive,
40    isDragAccept,
41    isDragReject
42  } = useDropzone({
43    onDrop,
44    accept: 'image/jpeg, image/png'
45  });
46
47  const style = useMemo(() => ({
48    ...baseStyle,
49    ...(isDragActive ? activeStyle : {}),
50    ...(isDragAccept ? acceptStyle : {}),
51    ...(isDragReject ? rejectStyle : {})
52  }), [
53    isDragActive,
54    isDragReject,
55    isDragAccept
56  ]);
57
58  return (
59    <div {...getRootProps({style})}>
60      <input {...getInputProps()} />
61      <div>Drag and drop your images here.</div>
62    </div>
63  )
64}
65
66export default DropzoneComponent;

此代码将产生以下结果:

Screenshot of React Dropzone with custom styles

更改该组件的接受和拒绝的外观可以帮助用户提供有关其文件是否有效的反馈。

步骤 4 – 添加图像预览

预览是将图像拖放到组件中的一份副本,有助于向用户提供视觉反馈,以验证他们选择的图像文件的内容。

预览在 7.0.0 版本中被删除,但是文档提供了通过Object.assign()URL.createObjectURL()的组合来读取它的一种替代方案。

修订您的DropzoneComponent,并修改它以使用预览:

 1[label src/DropzoneComponent.js]
 2import React, { useCallback, useEffect, useMemo, useState } from 'react';
 3import { useDropzone } from 'react-dropzone';
 4
 5const baseStyle = {
 6  display: 'flex',
 7  flexDirection: 'column',
 8  alignItems: 'center',
 9  padding: '20px',
10  borderWidth: 2,
11  borderRadius: 2,
12  borderColor: '#eeeeee',
13  borderStyle: 'dashed',
14  backgroundColor: '#fafafa',
15  color: '#bdbdbd',
16  transition: 'border .3s ease-in-out'
17};
18
19const activeStyle = {
20  borderColor: '#2196f3'
21};
22
23const acceptStyle = {
24  borderColor: '#00e676'
25};
26
27const rejectStyle = {
28  borderColor: '#ff1744'
29};
30
31function DropzoneComponent(props) {
32  const [files, setFiles] = useState([]);
33
34  const onDrop = useCallback(acceptedFiles => {
35    setFiles(acceptedFiles.map(file => Object.assign(file, {
36      preview: URL.createObjectURL(file)
37    })));
38  }, []);
39
40  const {
41    getRootProps,
42    getInputProps,
43    isDragActive,
44    isDragAccept,
45    isDragReject
46  } = useDropzone({
47    onDrop,
48    accept: 'image/jpeg, image/png'
49  });
50
51  const style = useMemo(() => ({
52    ...baseStyle,
53    ...(isDragActive ? activeStyle : {}),
54    ...(isDragAccept ? acceptStyle : {}),
55    ...(isDragReject ? rejectStyle : {})
56  }), [
57    isDragActive,
58    isDragReject,
59    isDragAccept
60  ]);
61
62  const thumbs = files.map(file => (
63    <div key={file.name}>
64      <img
65        src={file.preview}
66        alt={file.name}
67      />
68    </div>
69  ));
70
71  // clean up
72  useEffect(() => () => {
73    files.forEach(file => URL.revokeObjectURL(file.preview));
74  }, [files]);
75
76  return (
77    <section>
78      <div {...getRootProps({style})}>
79        <input {...getInputProps()} />
80        <div>Drag and drop your images here.</div>
81      </div>
82      <aside>
83        {thumbs}
84      </aside>
85    </section>
86  )
87}
88
89export default DropzoneComponent;

<$>[注] **注:**要避免记忆泄露,您需要拨打URL.revokeObjectURL(file.preview),以避免不必要地存储预览。

现在,每当一个文件(或文件)被丢弃时,该文件将附加到状态,并显示预览。

结论

在本教程中,您介绍了反应滴区以及如何在React应用程序中使用它,以提供高级拖放功能来上传文件。

如果您想了解更多关于 React 的信息,请查看我们的 如何在 React.js 中编码系列,或查看 我们的 React 主题页面以获取练习和编程项目。

Published At
Categories with 技术
Tagged with
comments powered by Disqus