如何用 React 完成图片上传功能
2017-05-24 16:21
435 查看
编辑推荐:稀土掘金,这是一个针对技术开发者的一个应用,你可以在掘金上获取最新最优质的技术干货,不仅仅是Android知识、前端、后端以至于产品和设计都有涉猎,想成为全栈工程师的朋友不要错过!
原文地址:Image Upload and Manipulation with React
本文已获得原作者 Damon Bauer 的授权
译文出自:掘金翻译计划
译者:DeadLion
校对者:mypchas6fans, Kulbear
下面这篇特邀文章是由 Damon Bauer 完成的,主题是关于一个 web 开发人员非常常见的工作:为用户提供图片上传功能。我想说这并不容易,但是有了一些功能强大的工具来帮忙做一些比较“重”的工作,这个任务会觉得比以前轻松许多。Damon
甚至全程在浏览器中完成了这项任务!
对于 web 开发者来说,让用户能够上传图片是一件很常见的事情。一开始可能看起来小菜一碟,但是当真正创建一个图片上传组件的时候,还是有些问题需要去考虑的。这里有一些注意事项:
允许什么类型的图片上传?
需要多大的图片? 这对性能有何影响?
图片长宽比例应该是多少?
如何管理图片? 能扑捉到不良图片吗?
图片存储在哪? 如何运维?
诸如 Paperclip 和 ImageProcessor 这样的服务器端工具,能解决上面大部分的问题。不幸的是,目前还没有一个能用在单页应用上的现成的工具。我将向你们展示我是如何在一个 React 应用中解决这个问题的,完全没有用到服务器端语言。
这是我们将要构建的应用的一个小样品。
我用到了下面三个工具:
react-dropzone 来接受用户的图片
superagent 转换上传的图片
Cloudinary 存储图片和编辑图片。
Cloudinary 是一个可以为图片提供存储、操作、管理、提供功能的云服务。我选择使用 Cloudinary 是因为它提供的免费账户包含了所有我所需要的功能。你至少需要一个免费帐户才能开始。
假如说你想裁剪,调整大小并给上传的图片增加滤镜。Cloudinary 有个转换的概念,和修改图片功能链接在一块的,不管你需不需要。一旦上传,就会转换、修改然后存储新的图片。
在 Cloudinary 控制面板中,找到 Settings > Upload,然后选择 “Upload presets” 下方 的 “Add upload preset”。
下一步,将 “Mode” 改成 “Unsigned”。这是必须的,然后你就可以不需要使用服务器端语言来处理私钥也能直接上传到 Cloudinary 了。
在 “Incoming Transformations” 部分选择 “Edit” 可以添加任何转换。 你可以裁剪、调整大小、改变质量、旋转、滤镜等等。保存预设,这就行了!你现在有地方上传、处理、存储图片了,能够为你的应用程序提供图片服务了。注意预设名称,我们稍后将用到它。让我们进入代码部分吧。
为了处理图片上传,我用了 react-dropzone 插件。它包含了一些功能,如拖放文件、文件类型限制和多文件上传。
首先,安装依赖。在命令行中输入下面的命令,运行:
npm install react react-dropzone superagent --save
然后在你的组件中导入 React、 react-dropzone 和 superagent。我使用 ES6 import 语法。
我们稍后会用到 superagent。现在,在你的组件 render 方法中包含一个react-dropzone 实例。
以下是这个组件的一些概要:
multiple={false} 同一时间只允许一个图片上传。
accept="image/*" 允许任何类型的图片。你可以明确的限制文件类型,只允许某些类型可以上传, 例如 accept="image/jpg,image/png"。
onDrop 是一个方法,当图片被上传的时候触发。
当使用 React ES5 类语法(React.createClass),所有方法是 “autobound(自动绑定)” 到类实例上。这篇文章中的代码使用 ES6 类语法(extends React.Component),不提供自动绑定的。所以我们在 onDrop 属性中用了 .bind(this) 。(如果你不熟悉 .bind,你可以看看这篇文章了解下。)
现在,让我们设置当上传一个图像时,做某些事情的方法。
首先,为两条重要的上传信息设置一个 const 。
上传预设 ID (当你创建了上传预设时自动生成)
你的 Cloudinary 上传 URL
然后,增加一条记录到组件初始化 state (使用 this.setState);我给这个属性起了个名字 uploadedFileCloudinaryUrl。最终,这将存放一个上传成功后由 Cloudinary 生成的图片 URL。我们稍后会用到这条 state。
react-dropzone 文档说它总是返回一个上传文件的数组,所以我们将该数组传递给 onImageDrop 方法的 files 参数。我们设置了一次只能传一张图片,所以图片总是在数组的第一个位置。
调用 handleImageUpload ,将图片(files[0])传入该方法。我将这个方法分离出一个单独的方法,遵循单一职责原则。从本质上讲,这一原则方法教你保持方法紧凑,只做一件事。
处理图片上传和转换
首先,用 superagent 将我们之前设置的两个 const POST 到 Cloudinary 。.field 方法 能让我们将数据附加到
POST 请求中。这些数据包含了 Cloudinary 处理上传图片的所有信息。通过调用 .end,执行请求并提供回调。
在 .end 回调中,打印所有返回错误的同时,最好也告诉用户出现了一个错误。
接下来,我们接收到的响应中包含一个 URL,检查下它是不是一个空字符串。这就是图片被上传,处理后 Cloudinary 生成的一个 URL。举个例子,如果一个用户正在编辑他的资料,上传了一张图片,你可以将 Cloudinary 返回的新的图片 URL 保存到你的数据库中。
我们目前写的代码,支持用户拖拽一张图片,组件将图片发送到 Cloudinary,然后收到一个给我们用的转换后的图片 URL。
组件最后一部分是一个 div,可以预览上传后的图片。
如果 uploadedFileCloudinaryUrl state 是一个空字符串,三元运算符将输出null (什么都没有)。回想下,组件的 uploadedFileCloudinaryUrl state 默认是一个空字符串;这就意味着组件渲染时,这个 div 将是空的。
然而,当 Cloudinary 返回一个 URL,state 不再是空字符串,因为我们在handleImageUpload 更新了 state。此时,该组件将重新渲染,显示上传的文件名称和变换后的图像的预览。
This is just the groundwork for an image upload component. There are plenty of additional features you could add, like:
这只是为图片上传组件做的准备工作。有很多可以添加的附加功能,比如:
允许多图片上传
清除上传的图片
如果因为某些原因上传失败,展示错误
使用移动设备相机作为上传源
目前为止,这些设置已经满足我工作的需求了。硬编码上传预设不是完美的,但我还没有碰到任何问题。
希望你们已经理解了如何不用服务器端语言,使用 React 就能上传,存储和操作图片。如果你们有任何问题或者点评,我很乐意听到你们的反馈!我已经建好了一个仓库,你们可以点击链接查看代码.
原文地址:Image Upload and Manipulation with React
本文已获得原作者 Damon Bauer 的授权
译文出自:掘金翻译计划
译者:DeadLion
校对者:mypchas6fans, Kulbear
下面这篇特邀文章是由 Damon Bauer 完成的,主题是关于一个 web 开发人员非常常见的工作:为用户提供图片上传功能。我想说这并不容易,但是有了一些功能强大的工具来帮忙做一些比较“重”的工作,这个任务会觉得比以前轻松许多。Damon
甚至全程在浏览器中完成了这项任务!
对于 web 开发者来说,让用户能够上传图片是一件很常见的事情。一开始可能看起来小菜一碟,但是当真正创建一个图片上传组件的时候,还是有些问题需要去考虑的。这里有一些注意事项:
允许什么类型的图片上传?
需要多大的图片? 这对性能有何影响?
图片长宽比例应该是多少?
如何管理图片? 能扑捉到不良图片吗?
图片存储在哪? 如何运维?
诸如 Paperclip 和 ImageProcessor 这样的服务器端工具,能解决上面大部分的问题。不幸的是,目前还没有一个能用在单页应用上的现成的工具。我将向你们展示我是如何在一个 React 应用中解决这个问题的,完全没有用到服务器端语言。
这是我们将要构建的应用的一个小样品。
工具包
我用到了下面三个工具:react-dropzone 来接受用户的图片
superagent 转换上传的图片
Cloudinary 存储图片和编辑图片。
设置 Cloudinary
Cloudinary 是一个可以为图片提供存储、操作、管理、提供功能的云服务。我选择使用 Cloudinary 是因为它提供的免费账户包含了所有我所需要的功能。你至少需要一个免费帐户才能开始。假如说你想裁剪,调整大小并给上传的图片增加滤镜。Cloudinary 有个转换的概念,和修改图片功能链接在一块的,不管你需不需要。一旦上传,就会转换、修改然后存储新的图片。
在 Cloudinary 控制面板中,找到 Settings > Upload,然后选择 “Upload presets” 下方 的 “Add upload preset”。
下一步,将 “Mode” 改成 “Unsigned”。这是必须的,然后你就可以不需要使用服务器端语言来处理私钥也能直接上传到 Cloudinary 了。
在 “Incoming Transformations” 部分选择 “Edit” 可以添加任何转换。 你可以裁剪、调整大小、改变质量、旋转、滤镜等等。保存预设,这就行了!你现在有地方上传、处理、存储图片了,能够为你的应用程序提供图片服务了。注意预设名称,我们稍后将用到它。让我们进入代码部分吧。
接受用户输入
为了处理图片上传,我用了 react-dropzone 插件。它包含了一些功能,如拖放文件、文件类型限制和多文件上传。首先,安装依赖。在命令行中输入下面的命令,运行:
npm install react react-dropzone superagent --save
然后在你的组件中导入 React、 react-dropzone 和 superagent。我使用 ES6 import 语法。
import React from 'react'; import Dropzone from 'react-dropzone'; import request from 'superagent';
我们稍后会用到 superagent。现在,在你的组件 render 方法中包含一个react-dropzone 实例。
export default class ContactForm extends React.Component { render() { <Dropzone multiple={false} accept="image/*" onDrop={this.onImageDrop.bind(this)}> <p>Drop an image or click to select a file to upload.</p> </Dropzone> }
以下是这个组件的一些概要:
multiple={false} 同一时间只允许一个图片上传。
accept="image/*" 允许任何类型的图片。你可以明确的限制文件类型,只允许某些类型可以上传, 例如 accept="image/jpg,image/png"。
onDrop 是一个方法,当图片被上传的时候触发。
当使用 React ES5 类语法(React.createClass),所有方法是 “autobound(自动绑定)” 到类实例上。这篇文章中的代码使用 ES6 类语法(extends React.Component),不提供自动绑定的。所以我们在 onDrop 属性中用了 .bind(this) 。(如果你不熟悉 .bind,你可以看看这篇文章了解下。)
处理拖拽图片
现在,让我们设置当上传一个图像时,做某些事情的方法。首先,为两条重要的上传信息设置一个 const 。
上传预设 ID (当你创建了上传预设时自动生成)
你的 Cloudinary 上传 URL
// import statements const CLOUDINARY_UPLOAD_PRESET = 'your_upload_preset_id'; const CLOUDINARY_UPLOAD_URL = 'https://api.cloudinary.com/v1_1/your_cloudinary_app_name/upload'; export default class ContactForm extends React.Component { // render()
然后,增加一条记录到组件初始化 state (使用 this.setState);我给这个属性起了个名字 uploadedFileCloudinaryUrl。最终,这将存放一个上传成功后由 Cloudinary 生成的图片 URL。我们稍后会用到这条 state。
export default class ContactForm extends React.Component { constructor(props) { super(props); this.state = { uploadedFileCloudinaryUrl: '' }; } }
react-dropzone 文档说它总是返回一个上传文件的数组,所以我们将该数组传递给 onImageDrop 方法的 files 参数。我们设置了一次只能传一张图片,所以图片总是在数组的第一个位置。
调用 handleImageUpload ,将图片(files[0])传入该方法。我将这个方法分离出一个单独的方法,遵循单一职责原则。从本质上讲,这一原则方法教你保持方法紧凑,只做一件事。
export default class ContactForm extends React.Component { constructor(props) { ... } onImageDrop(files) { this.setState({ uploadedFile: files[0] }); this.handleImageUpload(files[0]); } render() { ... } }
处理图片上传和转换
首先,用 superagent 将我们之前设置的两个 const POST 到 Cloudinary 。.field 方法 能让我们将数据附加到
POST 请求中。这些数据包含了 Cloudinary 处理上传图片的所有信息。通过调用 .end,执行请求并提供回调。
export default class ContactForm extends React.Component { constructor(props) { ... } onImageDrop(files) { ... } handleImageUpload(file) { let upload = request.post(CLOUDINARY_UPLOAD_URL) .field('upload_preset', CLOUDINARY_UPLOAD_PRESET) .field('file', file); upload.end((err, response) => { if (err) { console.error(err); } if (response.body.secure_url !== '') { this.setState({ uploadedFileCloudinaryUrl: response.body.secure_url }); } }); } render() { ... } }
在 .end 回调中,打印所有返回错误的同时,最好也告诉用户出现了一个错误。
接下来,我们接收到的响应中包含一个 URL,检查下它是不是一个空字符串。这就是图片被上传,处理后 Cloudinary 生成的一个 URL。举个例子,如果一个用户正在编辑他的资料,上传了一张图片,你可以将 Cloudinary 返回的新的图片 URL 保存到你的数据库中。
我们目前写的代码,支持用户拖拽一张图片,组件将图片发送到 Cloudinary,然后收到一个给我们用的转换后的图片 URL。
渲染阶段
组件最后一部分是一个 div,可以预览上传后的图片。export default class ContactForm extends React.Component { constructor(props) { ... } onImageDrop(files) { ... } handleImageUpload(file) { ... } render() { <div> <div className="FileUpload"> ... </div> <div> {this.state.uploadedFileCloudinaryUrl === '' ? null : <div> <p>{this.state.uploadedFile.name}</p> <img src={this.state.uploadedFileCloudinaryUrl} /> </div> } </div> </div> } }
如果 uploadedFileCloudinaryUrl state 是一个空字符串,三元运算符将输出null (什么都没有)。回想下,组件的 uploadedFileCloudinaryUrl state 默认是一个空字符串;这就意味着组件渲染时,这个 div 将是空的。
然而,当 Cloudinary 返回一个 URL,state 不再是空字符串,因为我们在handleImageUpload 更新了 state。此时,该组件将重新渲染,显示上传的文件名称和变换后的图像的预览。
结束
This is just the groundwork for an image upload component. There are plenty of additional features you could add, like:这只是为图片上传组件做的准备工作。有很多可以添加的附加功能,比如:
允许多图片上传
清除上传的图片
如果因为某些原因上传失败,展示错误
使用移动设备相机作为上传源
目前为止,这些设置已经满足我工作的需求了。硬编码上传预设不是完美的,但我还没有碰到任何问题。
希望你们已经理解了如何不用服务器端语言,使用 React 就能上传,存储和操作图片。如果你们有任何问题或者点评,我很乐意听到你们的反馈!我已经建好了一个仓库,你们可以点击链接查看代码.
相关文章推荐
- 黄聪:如何在wordpress任何一个页面调用“插入图片”按钮,实现上传图片功能
- 如何在wordpress任何一个页面调用“插入图片”按钮,实现上传图片功能
- React Native 使用react-native-image-picker库实现图片上传功能
- 如何用input标签和jquery实现多图片的上传和回显功能
- react native中如何往服务器上传网络图片
- CKeditor如何实现图片上传功能
- 《React-Native系列》26、 ReactNative实现图片上传功能
- react native中如何往服务器上传网络图片
- 如何实现无刷新安全图片上传功能
- 如何有效实现前端压缩图片并上传功能
- [PHP]移动端网页如何使用JqueryMobile+PHP实现上传图片的功能
- 牛腩购物32:完成整个网站的功能制作(后台产品列表,多表查询+分页),产品修改保存,图片的上传保存
- 利用系统相机和图库打造3分钟完成拍照,图片裁剪以及视频资源上传功能
- React+ajax+java实现上传图片并预览功能
- Bootstrap-Markdown如何添加本地图片上传功能
- 黄聪:如何在wordpress任何一个页面调用“插入图片”按钮,实现上传图片功能
- 我需要在Web上完成一个图片上传的功能
- 使用SringMvc完成文件和图片上传功能
- (转)React Native 使用react-native-image-picker库实现图片上传功能
- react 中 使用 没有启用图片上传功能的simditor 富文本编辑器