一次说清楚!图片上传怎么玩?原来我们知道的都太简单了

avatar
公众号:转转技术
原文链接: mp.weixin.qq.com

作者 | 王冠甲

随着我司的发展,前端开发同学在公司企业级的中台业务的重要性也在提高

我们正处在从IT时代到DT时代中的过渡阶段,各个企业都要面临信息化数字化的压力,如何提高内效是目前都要面临的一个问题,我司中台业务走到今天,既要好体验,也要高效率,给技术团队提出了一个有趣的问题

在我们日常项目开发中,图片上传是一个十分常见的场景。

而现在的各种UI框架都提供了自己的上传组件,网上第三方的上传组件也多如牛毛。可能你早已习惯了直接使用这些现成的组件,然而对于其具体的实现,却并未深入解析。

本文以图片上传为入口,将通过简单的代码,为你解析图片上传的各个知识点,让你一次打通任督二脉

孔子说过食不厌精、脍不厌细,他是说食物制作的越精细越好。在顺德,有一鱼八吃,各个都是经典味道,吃鱼的心思巧,全鱼宴的设计精妙,点点滴滴都是厨师的心血与骄傲!

为什么突然转到吃了,可能是临近中午,有些饿了,开个玩笑,不过各位同学不觉得食不厌精、脍不厌细也是在说我们的技术开发态度吗?

今天我给大家带来一传三精!


基本原理

  • Form表单提交

  • Ajax上传

Form表单提交

表单上传需要注意以下几点:

(1)提供form表单,method必须是post。

(2)form表单的enctype必须是multipart/form-data。

属性 说明
enctype 属性规定在发送到服务器之前应该如何对表单数据进行编码。默认地,表单数据会编码为 "application/x-www-form-urlencoded"。就是说,在发送到服务器之前,所有字符都会进行编码。 HTML表单如何打包数据文件是由enctype这个属性决定的。enctype有以下几种取值:
application/x-www-form-urlencoded 在发送前编码所有字符(默认)(空格被编码为’+’,特殊字符被编码为ASCII十六进制字符)。
multipart/form-data 不对字符编码。在使用包含文件上传控件的表单时,必须使用该值。
text/plain 空格转换为 “+” 加号,但不对特殊字符编码。

默认enctype=application/x-www-form-urlencoded,所以表单的内容会按URL规则编码,然后根据表单的提交方法:

Ajax上传

FormData( https://developer.mozilla.org/zh-CN/docs/Web/API/FormData)

对象是html5的一个对象,目前的一些主流的浏览器都已经兼容。

通过FormData对象可以更灵活方便的发送表单数据,因为可以独立于表单使用。如果你把表单的编码类型设置为multipart/form-data ,则通过FormData传输的数据格式和表单通过submit()方法传输的数据格式相同。

代码如下:


拖拽上传

主要是基于DataTransfer和FormData,通过借助dataTransfer和formData实现从电脑的资源管理器直接拖拽图片到网页上传,具体过程是从电脑拖拽图片到网页,js在drop的事件中取到当前事件对象的dataTransfer进而得到文件对象,然后实例化formData对象,借助xhr异步上传图片,这无疑是一个锦上添花的功能

实现代码如下:

dropEffect 将基于用户要求的动作被初始化设置:

监听事件进行处理:

Demo效果:


粘贴上传

这就今天要说的第三种吃法,剪切板图片粘贴上传

有三种方式可以在元素中粘贴内容:

  • 按下 CTRL + V

  • 从浏览器的编辑菜单中选择 "Paste(粘贴)"

  • 右击鼠标按钮在上下文菜单中选择 "Paste(粘贴)" 命令

实现原理是:通过clipboardData对象访问剪切板中的数据,转为Base64进行预览,使用FileReader对象,使用Bolb对象处理数据,添加到FormData中,通过AJAX传给服务器端

整个实现过程中,有几个知识点需要确定,且每个点都有不小的坑需要兼容,分别为

  • 监听剪切板事件

  • clipboardData

  • FileReader

  • FormData

clipboardData

它实际上是一个DataTransfer类型的对象,DataTransfer是拖动产生的一个对象,但实际上粘贴事件也是它。

clipboardData的属性

属性 类型 说明
dropEffect String 默认是 none
effectAllowed String 默认是 uninitialized
files FileList 粘贴操作为空List
items DataTransferItemList 剪切板中的各项数据
types Array 剪切板中的数据类型

访问剪贴板中的数据,可以:在IE中,clipboardData对象是window对象的属性;而在Chrome、Safari和Firefox 4+中,clipboardData对象是相应event对的属性。但是,在Chrome、Safari和Firefox 4+中,只有在处理剪贴板事件期间,clipboardData对象才有效,这是为了防止对剪贴板的未授权访问;在IE中,则可以随时访问clipboardData对象。为了确保跨浏览器兼容,最好只在发生剪贴板事件期间使用这个对象。

clipboardData对象有三个方法:getData()方法、setData()方法和clearData()方法。

getData()方法用于从剪贴板中获取数据,它接收一个参数,即要取得的数据格式。在IE中,有两种数据格式:’text”和”URL”。在Chrome、Safari和Firefox 4+中,这个参数是一种MIME类型;不过,可以用”text”代表”text/plain”。

setData()方法的第一个参数也是数据类型,第二个参数是要放在剪贴板中的文字。对于第一个参数,IE照样是支持”text”和”URL”,而在Chrome、Safari中,仍然支持MIME类型。但是与getData()方法不同的是,在Chrome、Safari中的setData()方法不能识别”text”类型。这两个浏览器在成功将文本放到剪贴板中后,都会返回true;否则返回false。

FileReader

FileReader 对象允许Web应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File 或 Blob 对象指定要读取的文件或数据。

事件处理 FileReader.onload处理load事件。该事件在读取操作完成时触发。

FileReader.onloadend处理loadend事件。该事件在读取操作结束时(要么成功,要么失败)触发。

方法 FileReader.readAsDataURL()开始读取指定的Blob中的内容。一旦完成,result属性中将包含一个data: URL格式的字符串以表示所读取文件的内容。

readAsDataURL: 该方法会读取指定的 Blob 或 File 对象。读取操作完成的时候,readyState 会变成已完成(DONE),并触发 loadend 事件,同时 result 属性将包含一个data:URL格式的字符串(base64编码)以表示所读取文件的内容。

实现代码如下:

触发粘贴事件后的操作: 

base64转二进制 

Demo效果: