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;
所以不要怕,如果我错了记得提醒下我啊。
目前为止其实已经该说的都差不多覆盖到了吧,动手能力强的话已经可以根据教程写一个实例出来的了。我看情况要不要加一个实战代码做系列结尾。