关于前端上传文件全面基础扫盲贴(四) ----- FileReader
系列文章
关于前端上传文件全面基础扫盲贴(零)
关于前端上传文件全面基础扫盲贴(一) ----- XMLHttpRequest
关于前端上传文件全面基础扫盲贴(二) ----- File
关于前端上传文件全面基础扫盲贴(三) ----- FormData
关于前端上传文件全面基础扫盲贴(四) ----- FileReader
关于前端上传文件全面基础扫盲贴(五) ----- H5拖拽事件
关于前端上传文件全面基础扫盲贴(六) ----- 图片上传,旋转,重绘,预览等实战(附DEMO)
FileReader对象(知识点主要来源于关于FileReader API)
摘自上面来源,分析的挺好,我又无耻得搬下来了:
使用FileReader
对象,web应用程序可以异步的读取存储在用户计算机上的文件(或者原始数据缓冲)内容,可以使用File
对象或者Blob
对象来指定所要处理的文件或数据.其中File对象可以是来自用户在一个<input>元素上选择文件后返回的FileList
对象,也可以来自拖放操作生成的DataTransfer
对象,还可以是来自在一个HTMLCanvasElement
上执行mozGetAsFile()方法后的返回结果.
在这里作用就是当你上传图片之后,可以直接从本地先读取出原始数据,然后在页面上展示出来,就是传说中的预览图片功能,在上传到后台前就已经能先拿原始数据来使用了
看看兼容性如何(温馨提示:下图只代表支持程度,支持归支持,不一定百分百支持,所以用到部分方法时不兼容时正常的)
创建一个FileReader对象:
var reader = new FileReader();
事件处理程序:
事件 | 描述 |
---|---|
onabort | 当读取操作被中止时调用 |
onerror | 当读取操作发生错误时调用 |
onload | 当读取操作成功完成时调用 |
onloadend | 当读取操作完成时调用,不管是成功还是失败.该处理程序在onload或者onerror之后调用 |
onloadstart | 当读取操作将要开始之前调用 |
onprogress | 在读取数据过程中周期性调用 |
abort | 中止该读取操作.在返回时,readyState属性的值为DONE.当该FileReader对象没有在进行读取操作时(也就是readyState属性的值不为LOADING时),调用abort()方法会抛出异常DOM_FILE_ABORT_ERR |
下面方法会开始读取指定的Blob对象或File对象中的内容. 当读取操作完成时,readyState属性
的值会成为DONE
,如果设置了onloadend
事件处理程序,则调用之.区别在于:
属性 | 描述 |
---|---|
readAsArrayBuffer | result属性中将包含一个ArrayBuffer对象以表示所读取文件的内容 |
readAsBinaryString | result属性中将包含所读取文件的原始二进制数据 |
readAsDataURL | result属性中将包含一个data: URL格式的字符串以表示所读取文件的内容.(这个就是实现我们预览的重要方法了!!!!!) |
readAsText | result属性中将包含一个字符串以表示所读取的文件内容 |
介绍到这里就差不多了,接下来看看怎么实现不提交后台实现预览图片,这里只展示这部分功能先
示例
<!doctype html> <html> <head> <meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/> <title></title> <script type="text/javascript"> var oFReader = new FileReader(); oFReader.onload = function (oFREvent) { document .getElementById("uploadPreview") .src = oFREvent.target.result; }; function loadImageFile() { if (document.getElementById("uploadImage").files.length === 0) return; var oFile = document .getElementById("uploadImage") .files[0]; oFReader.readAsDataURL(oFile); } </script> </head> <body> <form name="uploadForm"> <img id="uploadPreview"/> <input id="uploadImage" type="file" name="myPhoto" onchange="loadImageFile();"/> </form> </body> </html>
你看,其实很简单,没什么复杂代码,只是需要的范围比较广,为了一个上传图片已经折腾了多少知识点了,还没完呢...o(一︿一+)o
回归正题,说说几个要点,首先看看代码的document.getElementById("uploadImage")
出现了好几次了,是不是好碍眼?是不是好想优化?是不是想为什么不把他放到一个变量存起来算了?
不行的,因为当你存一个变量之后再上传文件,你就找不到FileReader对象了,详情可以参考一下我之前写的关於Javascript基本类型和引用类型小知识
然后oFReader.onload里面的oFREvent就是你能够拿到的数据了,里面大概长这样子的,看的眼花缭乱,你们可以慢慢挖掘
其中:
readyState: 0-还没有加载任何数据.1-数据正在被加载.2-已完成全部的读取请求.
result: 返回文件的内容。只有在读取操作完成后,此属性才有效,返回的数据的格式取决于是使用哪种读取方法来执行读取操作的。
中间插播一则消息吧,图中可看到一个result属性的地址,那是一个base64 编码.就是可以将一副图片数据编码成一串字符串,使用该字符串代替图像地址。
我们所看到的网页上的每一个图片,都是需要消耗一个 http 请求下载而来的,后面因此诞生的精灵图就是基于这个问题才出来,不过局限性比较大,很难适用到所有项目
详情可以参考一下【前端攻略】:玩转图片Base64编码
另外就是兼容问题,因为懒得一个个去验证,就没写上去,不过查过资料放下来给你们,可能有用到,详情可以参考一下
对于 Chrome、Firefox、IE10 使用 FileReader
来实现。
对于 IE6~9 使用滤镜 filter:progid:DXImageTransform.Microsoft.AlphaImageLoader
来实现。
<!doctype html> <html> <head> <meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/> <title></title> <script type="text/javascript"> var loadImageFile = (function () { if (window.FileReader) { var oPreviewImg = null, oFReader = new window.FileReader(), rFilter = /^(?:image\/bmp|image\/cis\-cod|image\/gif|image\/ief|image\/jpeg|image\/jpeg|image\/jpeg|image\/pipeg|image\/png|image\/svg\+xml|image\/tiff|image\/x\-cmu\-raster|image\/x\-cmx|image\/x\-icon|image\/x\-portable\-anymap|image\/x\-portable\-bitmap|image\/x\-portable\-graymap|image\/x\-portable\-pixmap|image\/x\-rgb|image\/x\-xbitmap|image\/x\-xpixmap|image\/x\-xwindowdump)$/i; oFReader.onload = function (oFREvent) { if (!oPreviewImg) { var newPreview = document.getElementById("imagePreview"); oPreviewImg = new Image(); newPreview.appendChild(oPreviewImg); } oPreviewImg.src = oFREvent.target.result; }; return function () { var aFiles = document .getElementById("imageInput") .files; if (aFiles.length === 0) return; if (!rFilter.test(aFiles[0].type)) { alert("You must select a valid image file!"); return; } oFReader.readAsDataURL(aFiles[0]); } } else if (navigator.appName === "Microsoft Internet Explorer") { return function () { document .getElementById("imagePreview") .filters .item("DXImageTransform.Microsoft.AlphaImageLoader") .src = document .getElementById("imageInput") .value; } } })(); </script> <style type="text/css"> #imagePreview { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale); } </style> </head> <body> <input id="imageInput" type="file" name="myPhoto" onchange="loadImageFile();"/> <div id="imagePreview"></div> </body> </html>
没有IE浏览器测试,所以不知道是不是有效,其实里面看起来比我写的那个复杂,实际上多了个检验格式:
rFilter = /^(?:image\/bmp|image\/cis\-cod|image\/gif|image\/ief|image\/jpeg|image\/jpeg|image\/jpeg|image\/pipeg|image\/png|image\/svg\+xml|image\/tiff|image\/x\-cmu\-raster|image\/x\-cmx|image\/x\-icon|image\/x\-portable\-anymap|image\/x\-portable\-bitmap|image\/x\-portable\-graymap|image\/x\-portable\-pixmap|image\/x\-rgb|image\/x\-xbitmap|image\/x\-xpixmap|image\/x\-xwindowdump)$/i;
IE上兼容写法:
document.getElementById("imagePreview").filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = document.getElementById("imageInput").value;
所以不要怕,如果我错了记得提醒下我啊。
目前为止其实已经该说的都差不多覆盖到了吧,动手能力强的话已经可以根据教程写一个实例出来的了。我看情况要不要加一个实战代码做系列结尾。