如何使用react-dropzone在React中创建拖放文件上传
介绍
react-dropzone 是一个兼容 HTML5 的 React 组件,用于处理文件的拖放。
HTML5 支持使用 [1] 上传文件。 react-dropzone
为您提供附加功能,例如自定义放置区、显示预览以及限制文件类型和数量。
注意: 如果您使用 Vue 而不是 React,请参阅我们的 vue-dropzone 教程。
在本教程中,您将了解如何将 react-dropzone
添加到您的 React 项目并探索它提供的一些功能。
先决条件
要完成本教程,您需要:
- Node.js 的本地开发环境。 关注【X7X】如何安装Node.js并创建本地开发环境【X76X】。
本教程已使用 Node v15.3.0、npm
v7.4.0、react
v17.0.1 和 react-dropzone
v11.2.4 进行了验证。
第 1 步 — 设置项目
首先使用 create-react-app 生成 React App,然后安装依赖项:
npx create-react-app react-dropzone-example
切换到新的项目目录:
cd react-dropzone-example
安装react-dropzone
:
npm install react-dropzone@11.2.4
此时,您有了一个带有 react-dropzone
的新 React 项目。
第 2 步 — 添加 Dropzone 组件
react-dropzone
具有默认设置,允许您以最少的配置添加它。
至少,您将需要一个 onDrop
属性来处理删除的文件和一些号召性用语文本,以帮助限制任何用户混淆:
src/DropzoneComponent.js
import React, { useCallback } from 'react'; import { useDropzone } from 'react-dropzone'; function DropzoneComponent() { const onDrop = useCallback(acceptedFiles => { console.log(acceptedFiles); }, []); const { getRootProps, getInputProps } = useDropzone({ onDrop }); return ( <div {...getRootProps()}> <input {...getInputProps()} /> <div>Drag and drop your images here.</div> </div> ) } export default DropzoneComponent;
此代码为您的应用程序提供拖放功能。
注意: 值得注意的是,尽管 react-dropzone
是为拖放文件而设计的,但默认情况下它确实接受到 dropzone 的单击事件,这将启动一个文件选择对话框。
将组件添加到您的 React 应用程序:
src/App.js
import DropzoneComponent from './DropzoneComponent'; function App() { return ( <div className="App"> <DropzoneComponent /> </div> ); } export default App;
运行您的应用程序并在 Web 浏览器中观察它。 您应该会看到一个带有文本的 div:Drag and drop your images here
。
尝试将各种文件拖放到 React Dropzone 组件。 该代码当前使用 console.log
来显示文件。 上传文件的信息包括name
、lastModified
、size
和type
。
至此,你有了一个使用默认配置的 React Dropzone 组件。 react-dropzone
文档附加配置选项。
第 3 步 — 设置 Dropzone 组件的样式
默认情况下,react-dropzone
没有样式。 该文档提供了通用外观的样式,该外观使用弹性框和虚线边框的组合来向用户指示拖放文件的区域。
react-dropzone
还支持组件主动交互(isDragActive
)、接受文件(isDragAccept
)或拒绝文件(isDragReject
)时的道具.
重新访问您的 DropzoneComponent
并将其修改为在应用于 JPEG 和 PNG 图像文件类型时使用 isDragActive
、isDragAccept
和 isDragReject
:
src/DropzoneComponent.js
import React, { useCallback, useMemo } from 'react'; import { useDropzone } from 'react-dropzone'; const baseStyle = { display: 'flex', flexDirection: 'column', alignItems: 'center', padding: '20px', borderWidth: 2, borderRadius: 2, borderColor: '#eeeeee', borderStyle: 'dashed', backgroundColor: '#fafafa', color: '#bdbdbd', transition: 'border .3s ease-in-out' }; const activeStyle = { borderColor: '#2196f3' }; const acceptStyle = { borderColor: '#00e676' }; const rejectStyle = { borderColor: '#ff1744' }; function DropzoneComponent(props) { const onDrop = useCallback(acceptedFiles => { console.log(acceptedFiles); }, []); const { getRootProps, getInputProps, isDragActive, isDragAccept, isDragReject } = useDropzone({ onDrop, accept: 'image/jpeg, image/png' }); const style = useMemo(() => ({ ...baseStyle, ...(isDragActive ? activeStyle : {}), ...(isDragAccept ? acceptStyle : {}), ...(isDragReject ? rejectStyle : {}) }), [ isDragActive, isDragReject, isDragAccept ]); return ( <div {...getRootProps({style})}> <input {...getInputProps()} /> <div>Drag and drop your images here.</div> </div> ) } export default DropzoneComponent;
此代码将产生以下结果:
更改接受和拒绝组件的外观有助于向用户提供有关其文件是否有效的反馈。
第 4 步 — 添加图像预览
预览是在组件中拖放的图像的副本。 这有助于向用户提供视觉反馈,以验证他们选择的图像文件的内容。
预览在版本 7.0.0 中被删除,但是,文档提供了一种替代方法,可以使用 Object.assign()
和 URL.createObjectURL()
的组合来读取它。
重新访问您的 DropzoneComponent
并将其修改为使用 preview
:
src/DropzoneComponent.js
import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { useDropzone } from 'react-dropzone'; const baseStyle = { display: 'flex', flexDirection: 'column', alignItems: 'center', padding: '20px', borderWidth: 2, borderRadius: 2, borderColor: '#eeeeee', borderStyle: 'dashed', backgroundColor: '#fafafa', color: '#bdbdbd', transition: 'border .3s ease-in-out' }; const activeStyle = { borderColor: '#2196f3' }; const acceptStyle = { borderColor: '#00e676' }; const rejectStyle = { borderColor: '#ff1744' }; function DropzoneComponent(props) { const [files, setFiles] = useState([]); const onDrop = useCallback(acceptedFiles => { setFiles(acceptedFiles.map(file => Object.assign(file, { preview: URL.createObjectURL(file) }))); }, []); const { getRootProps, getInputProps, isDragActive, isDragAccept, isDragReject } = useDropzone({ onDrop, accept: 'image/jpeg, image/png' }); const style = useMemo(() => ({ ...baseStyle, ...(isDragActive ? activeStyle : {}), ...(isDragAccept ? acceptStyle : {}), ...(isDragReject ? rejectStyle : {}) }), [ isDragActive, isDragReject, isDragAccept ]); const thumbs = files.map(file => ( <div key={file.name}> <img src={file.preview} alt={file.name} /> </div> )); // clean up useEffect(() => () => { files.forEach(file => URL.revokeObjectURL(file.preview)); }, [files]); return ( <section> <div {...getRootProps({style})}> <input {...getInputProps()} /> <div>Drag and drop your images here.</div> </div> <aside> {thumbs} </aside> </section> ) } export default DropzoneComponent;
注意: 为避免内存泄漏,您需要调用 URL.revokeObjectURL(file.preview)
以避免不必要地存储预览。
现在,每当一个文件(或多个文件)被删除时,该文件将被附加到状态并显示预览。
结论
在本教程中,您了解了 react-dropzone
以及如何在 React 应用程序中使用它来为文件上传提供高级拖放功能。
如果您想了解有关 React 的更多信息,请查看我们的 如何在 React.js 中编码,或查看 我们的 React 主题页面 以了解练习和编程项目。