~~~针对需要读取本地图像,并立即显示在浏览器的情况,由于chrome firefox出于安全限制,input file并不返回文件的真实路径,经测试IE6/7/8都会返回真实路径,所以chrome, firefox无法直接将图像显示在页面上,这里刚好可以用到 FileReader这个东东
我们曾经在《HTML5 中 File 对象初探》中,使用到了FileReader,在那篇文章中,它被用来将一个文件读取为二进制字符串,并通过 xhr 发送到后端形成交互。作为 File API 的一部分,FileReader 专门用于读取文件,根据 W3C 的定义,FileReader 接口 "提供一些读取文件的方法与一个包含读取结果的事件模型"。
接下来,我们将逐一了解 FileReader 的方法与事件模型,并最终通过一个例子程序来应用 FireRead,在这个例子中,使用支持 FileReader 浏览器的用户将能够通过一个 file input 选择一个图像文件,并不经过后台将图像显示在页面中。下面的链接指向这个例子,值得注意的是,到目前为止,只有 Firefox 3.6+ 和 Chrome 6.0+ 实现了 FileReader 接口。~~~较新的chrome firefox都实现了FileReader接口
在这之前的 web 应用程序中,实现这个效果的通常做法是将用户选择的图像文件传送至后端,后端对其进行存储,再将 URL 返回到前端,前端通过这个 URL 来显示图像。 FileReader 的突破在于使得 JavaScript 拥有了处理文件的能力,它可以异步地读取存储在用户电脑中的文件,这里所指的文件,对于 JavaScript 来说是一个 File 对象,FileReader 读取文件的全部方法皆依赖于此,对于 File 对象还不是很了解的话,请先阅读《HTML5 中 File 对象初探》,这是本文的基础。
1. 特性检测与创建实例
检测一个浏览器是否支持 FileReader 很容易做到,支持这一接口的浏览器有一个位于 window 对象下的 FileReader 构造函数,如果浏览器有这个构造函数,那么就可以 new 一个 FileReader 的实例来使用。
if ( typeof FileReader === 'undefined' ) { alert( " 您的浏览器未实现 FileReader 接口 " ); } else { var reader = new FileReader(); // do sth. }
2. 方法
FileReader 的实例拥有 4 个方法,其中 3 个用以读取文件,另一个用来中断读取。下面的表格列出了这些方法以及他们的参数和功能,需要注意的是 ,无论读取成功或失败,方法并不会返回读取结果,这一结果存储在 result属性中。
方法名 | 参数 | 描述 |
---|---|---|
abort | none | 中断读取 |
readAsBinaryString | file | 将文件读取为二进制码 |
readAsDataURL | file | 将文件读取为 DataURL |
readAsText | file, [encoding] | 将文件读取为文本 |
readAsText: 该方法有两个参数,其中第二个参数是文本的编码方式,默认值为 UTF-8。这个方法非常容易理解,将文件以文本方式读取,读取的结果即是这个文本文件中的内容。
readAsBinaryString: 这个方法在《HTML5 中 File 对象初探》中已经被使用过一次了,它将文件读取为二进制字符串,通常我们将它传送到后端,后端可以通过这段字符串存储文件。
readAsDataURL: 这是例子程序中用到的方法,该方法将文件读取为一段以 data: 开头的字符串,这段字符串的实质就是 Data URI,Data URI是一种将小文件直接嵌入文档的方案。这里的小文件通常是指图像与 html 等格式的文件。点击这里了解更多关于 Data URI 的知识。
3. 事件
FileReader 包含了一套完整的事件模型,用于捕获读取文件时的状态,下面这个表格归纳了这些事件。
事件 | 描述 |
---|---|
onabort | 中断时触发 |
onerror | 出错时触发 |
onload | 文件读取成功完成时触发 |
onloadend | 读取完成触发,无论成功或失败 |
onloadstart | 读取开始时触发 |
onprogress | 读取中 |
文件一旦开始读取,无论成功或失败,实例的 result 属性都会被填充。如果读取失败,则 result 的值为 null ,否则即是读取的结果,绝大多数的程序都会在成功读取文件的时候,抓取这个值。
reader.onload = function () { this.result // 读取结果 }
4. 实例
了解了这些知识过后,我们来还原之前的示例。第一步,创建 html 部分,主要包括一个 input 和一个用来呈现结果的 div:
<p> <label>请选择一个图像文件:</label> <input type="file" id="demo_input" /> </p> <div id="demo_result"> <!-- 这里用来显示读取结果 --> </div>
接下来获取节点,并处理浏览器兼容部分,对于未实现 FileReader 接口的浏览器将给出一个提示并禁用 input,否则监听 input 的 change 事件。
if ( typeof FileReader === 'undefined' ){ result.innerHTML = "<p class='warn'>抱歉,你的浏览器不支持 FileReader</p>"; input.setAttribute( 'disabled','disabled' ); } else { input.addEventListener( 'change',readFile,false ); }
最后书写函数 readFile 的代码,当 file input 的 change 事件触发时,调用这个函数,首先获取到 file 对象,并通过 file 的 type 属性来检验文件类型,在这里,我们只允许选择图像类型的文件。然后创建一个 FileReader 实例,并且调用 readAsDataURL 方法读取文件,在实例的 load 事件中,获取到成功读取到的文件内容,并以插入一个 img 节点的方式,显示在页面中。
function readFile(){ var file = this.files[0]; //~~~ file为用户选择的文件 type的指为文件的mime if(!/image/w+/.test(file.type)){ alert("请确保文件为图像类型"); return false; } var reader = new FileReader(); reader.readAsDataURL(file); //~~~readAsDataURL reader.onload = function(e){ result.innerHTML = '<img src="'+this.result+'" alt=""/>' //~~直接将reader.result赋值给src属性,reader.result为DataURL } }
读取并显示本地图片实践:
var himgCH; //头像在320视窗中的计算高度 $(function(){ var supportFileReader; try{ if( (typeof FileReader) =='function') supportFileReader = true;}catch(e){ supportFileReader=false; } var isie = navigator.userAgent.toLowerCase().indexOf('msie')>=0; $('#himgfile').change(function(){ if(navigator.userAgent.toLowerCase().indexOf('msie')<0 || supportFileReader ){ //(!ie or ie10) chrome , firefox var file = this.files[0]; //用户选择的文件 if(! /image/w+/.test(file.type) ){ //file.type 文件的mime值 alert("请选择图像文件"); }else{ var reader = new FileReader(); reader.readAsDataURL(file);//用户选择的文件readAsDataURL reader.onload = function(){ // $('#pic4up').attr('src',this.result); $('#p_up').attr('src', this.result); $('#p_prev').attr('src', this.result); var img = new Image(); img.src = this.result; setTimeout(function(){ //不能马上获得img的计算高度 适当延时 // console.log(img.width); $('#scale').val( img.width/320 ); himgCH = $('#p_up').height(); $('#p_up').height(himgCH); $('#p_up').imgAreaSelect({aspectRatio:'1:1', onSelectChange: preview}); },100 ); } } }else{ //ie 6 7 8 //alert('using ie8- , file value:' + this.value); // $('#pic4up')[0].src=this.value; this.select(); // $('#pic4up')[0].src = document.selection.createRange().text; var img = new Image(); //alert('choose file path:' + document.selection.createRange().text ); var fpath = document.selection.createRange().text; //获取文件域的路径 // $('#p_prev')[0].src = img.src = $('#p_up')[0].src = fpath; //文件本地路径 赋值给img.src 实现预览 //AlphaImageLoader实现预览 关键点: AlpahaImageLoader src=本地路径 加载的是客户端文件系统的本地路径 AlphaImageLoader加载的图片位于 容器背景和内容之间 img.src = fpath; //获取图片的原始尺寸 $('#p_prev,#p_up').each(function(i, ele, eles){ this.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale);"; this.filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = fpath; if(this.id == 'p_prev') this.src = 'images/blank320_320.gif'; }); setTimeout(function(){ //不能马上获得img的计算高度 适当延时 // alert(img.width); $('#scale').val(img.width/320); himgCH = $('#p_up').height(); $('#p_up').height(himgCH); $('#p_up').imgAreaSelect({aspectRatio:'1:1', onSelectChange: preview}); },100 ); } //$('.iMask').removeClass('hide'); $('.btn_disable').addClass('btn_enable'); }); //---------------- function preview(img,selection){ //previewBox:150*150 var scaleX = 150 / selection.width; var scaleY = 150 / selection.height; $('#p_prev').css({ //预览小图做相应的大小调整和定位 Math.round(scaleX * 320) + 'px', height: Math.round(scaleY * himgCH) + 'px', marginLeft: '-' + Math.round(scaleX * selection.x1) + 'px', marginTop: '-' + Math.round(scaleY * selection.y1) + 'px' }); // 增加原图的缩小倍数因素 调整坐标值 var zoom = +$('#scale').val(); $('#x1').val(selection.x1*zoom); $('#y1').val(selection.y1*zoom); $('#x2').val(selection.x2*zoom); $('#y2').val(selection.y2*zoom); $('#w').val(selection.width*zoom); $('#h').val(selection.height*zoom); }