您的位置:首页 > Web前端 > JavaScript

【javascript】File API 读取并显示本地图片 -1

2015-04-22 16:46 393 查看
在过去,浏览器是不允许我们读取本地的文件,包括图片。因此,当我们需要预览一个图片的时候,往往先将它传送到服务端,然后服务端返回一个访问url地址,达到预览图片的功能。而如今,随着标准不断的改善,javascript里的API越来越多,我们可以通过直接读取本地文件的方式,加载我们想要看到的文本或者图片,一定程度上减少了服务端的压力。

接下来我们说一下运行环境和使用的库:

1. chrome 浏览器

2. zepto.js

其实在之前,我们有介绍过javascript里的 File 对象,它只能通过 input[type=file]元素获取。当用户触发了文件控件的onclick事件,同时选择了某一个文件确认时,触发文件控件的onchange事件。

一 : 案例页面结构

<body>
<article>
<header id="header"><h1>文件上传</h1></header>
<section class="box">
<form id="form" enctype='multipart/form-data' method='post'   action='#'>
<div class="upload-label"><h2>请选择文件</h2></div>
<div class="upload-box add-button"></div>
<button class="upload-button" type="submit">上传</button>
<input type="file" name="files"  id="files" >
</form>
</section>

</article>
</body>


主要关注的一点是
<input type="file" name="files"  id="files" >
我们这个form表单中存在这一个input[type=file]的元素,只有通过这一个接口,我们才可已调用电脑的文件管理器资源。因此很多时候我们会重写打开文件的界面,因为原生的界面的确不符合我们的审美。

下面是一张我写的一个简单的界面,相比之前有了很好的改善。



这是在手机上的一个显示,在这里我们就不纠结css样式了。直接看重点吧。

二: 通过zepto库绑定dom元素的事件

$(function(){
var maxlen = 5,    //文件可读取最大长度
filelist = [],    //存放 File对象数组
index = 0;    //当前存放File的长度

// 按钮元素监听click事件,执行add方法
$(".add-button").bind('click',add);

// input[type=file]元素监听change事件 执行filter方法
$("#files").bind('change',filter);

// 模拟input[type=file]添加文件的动作
function add(e){
if (index < maxlen ){
$("#files").trigger("click");
}else{
// 超过了选中文件文件的限制
// AnimateUtils.info('超过最大上传限制');
}
}
//  过滤文件类型
function filter(e){
var files = e.target.files,   // 获取本地文件File对象集合
typelist = ["image/jpeg","image/png"],  // 合法文件type列表
filetype, // 当前文件的类型
isPic;  // 文件类型是否合法标识

//  针对PC端多选的情况,前提是 input[type=file]元素包含 multiple属性

for (var i =0,len=files.length; i <len && index < 5 ;i++){
filetype  = files[i].type;
//判断filetype是否属于图片
isPic= typelist.some(function(item){return item == filetype;});
if(isPic){
filelist.push(files[i]);  //添加至文件列表
addImage(files[i]);   //同时添加到页面
index++;
}else{
// 提示文件非图片
// AnimateUtils.info('不支持的文件类型');
}
}
}
});


这里可能写的比较乱,我们来好好梳理一下,首先当用户点击了
<div class="upload-box add-button"></div>
元素时,它会trigger(触发 )
<input type="file" name="files"  id="files" >
的click事件。这么一来,就好像是点击了”文件控件”的按钮一样。



三:重点 : 理解File类型

我们是如何获取到File类型的实例的呢 ? 答案就是在
<input type="file" name="files"  id="files" >
这个元素里。一旦你绑定了它的onchange事件,它会将你选中的文件进行封装成一个File类型的实例。存放在目标元素的files引用中,接下来我们可以来看看这个对象实例到底是怎么样的。



原来files引用的是一个FileList集合,里面存放了File类型的数据, 每一个File类型都包含以下5个主要的参数。

lastModified #保存的是一个时间戳,表示文件最后修改的时间

lastModifiedDate #保存的是一个Date类型,是时间戳翻译的格式

name #保存的是我们选择的文件的名称

size #文件的大小 单位是字节

type #文件的类型 如果没有特定的类型,比如说文本文件,一般为空字符串

其实我们截图中,还可以发现File类型是继承Blob类型的,因此文件可以通过文本的方式进行读取。在我们上面的代码中,其实有一个addImage方法并没有介绍,其实它主要就是将这个指向本地文件的引用对象通过某种方式读取到浏览器中。这种方式就是借用了第二要说的类型,FileReader类型。

四 : 介绍FileReader类型

我们都知道一个文件要是很大的话,直接读取会导致操作阻塞,必须得要等文件读取完后才可以进行其他操作。而FileReader类型实现的就是异步文件读取机制。书上说,可以把它当做XMLHttpRequest对象,区别在于它面向的是本地文件系统,而XMLHttpRequest是面向远程服务器。

接下来我们来继续完善上面的例子,把FileReader类型的对象实例创建出来,然后对File类型的实例操作。

// 将图片加载至浏览器中,并且显示出来
function addImage(file){

// 创建 一个FileReader对象
var reader = new FileReader();
// 读取文件作为URL可访问地址
reader.readAsDataURL(file);

// 监控读取加载过程
reader.onprogress =function(e){

// 是否支持获取当前读取文件长度
if(e.lengthComputable){

// 将新创建的一个展示区域元素存放在 reader.uploadBox 中
reader.uploadBox= reader.uploadBox || $('<div class="upload-box"></div>').insertBefore('.add-button');
// 读取进度显示
reader.uploadBox.text( Math.ceil((e.loaded / e.total) * 100) +"%");

}

//异步加载文件成功
reader.onload = function(e){
// this 对象为reader
// reader.result 表示图片地址
reader.uploadBox.wrapInner('<img style="width:100%;height:100%; padding:.2rem;" src="'+reader.result+'" alt="'+file.name+'" />');
}

}


这里发现我们只是使用了FileReader类型里的 readAsDataURL方法,还有onprogress事件和onload事件。很明显,想要学习FileReader类型,这个例子还是不够的。接下来我们来看看FileReader类型可以使用的方法和监听事件。

可用方法:

1. readAsText(file,encoding) 将以纯文本的形式读取文件,可以指定编码类型,结果保存在result属性中。

2. readAsDataURL(file) 读取文件并将文件以数据URI的方式保存在result属性中。

3. readAsBinaryString(file) 读取文件并将一个字符串保存在result属性中,其中一个字符表示一个字节。

4. readAsArrayBuffer(file) 读取文件并将一个包含文件内容的ArrayBuffer保存在result属性中。

可用事件:

error事件

读取失败后触发, 失败的原因可能为 未找到文件,安全性错误,读取中断,文件不可读,编码错误.错误都会以数字的形式存放在code属性中。

progress事件

正在读取中触发,每50ms触发一次 其中event对象会包含 lengthComputable , loaded , total 属性。分别表示是否可以计算长度,当前加载长度和总共需要加载长度。

load事件 读取完毕后触发

error事件和load事件是不可以同时触发的,因为完成与完成失败是完全对立的结果。

我们来看一下加载图片成功后显示的页面吧



当我继续添加文件的时候,js判断超过了显示的长度,禁止文件继续添加。不过我们可以看到图片确实被加载到浏览器中,我们来看看这个img元素的src属性是什么样子的。



可以看到本地URI地址的前缀含有data:image/jpeg;的标示,可以告知浏览器这个地址是一个图片的格式。可以用图片的方式进行渲染。所以不能和其它方法进行换用。

五 : 使用另外一种方式加载URL地址

其实还有另外的一种方式可以直接读取URL地址,而这种方法就是直接丢给浏览器去渲染。我们只要调用方法就可以了。详细的代码如下

//创建对象的 URL资源
function createObjectURL(blob){
if(window.URL){
return window.URL.createObjectURL(blob);
}else if(window.webkitURL){
return window.webkitURL.createObjectURL(blob);
}
return null;
}
//销毁对象的URL资源
function revokeObjectURL(url){
if(window.URL){
return window.URL.revokeObjectURL(blob);
}else if(window.webkitURL){
return window.webkitURL.revokeObjectURL(blob);
}
}


这种使用方式的存在,我们就不需要什么注册监听事件了,直接调用一个方法就可以将File类型的文件读取,并且返回一个URL地址.我们修改一下addImage方法。

function addImage(file){

function createObjectURL(blob){
if(window.URL){
return window.URL.createObjectURL(blob);
}else if(window.webkitURL){
return window.webkitURL.createObjectURL(blob);
}
return null;
}
function revokeObjectURL(url){
if(window.URL){
return window.URL.revokeObjectURL(blob);
}else if(window.webkitURL){
return window.webkitURL.revokeObjectURL(blob);
}
}
$('<div class="upload-box"></div>').wrapInner('<img style="width:100%;height:100%; padding:.2rem;" src="'+createObjectURL(file)+'" alt="'+file.name+'" />').insertBefore('.add-button');
}




我们看到这个结果后,就知道它的处理方式和我们FileReader方式不一样了。至于具体的原理呢,目前还未知道,不过肯定的是,使用createObjectURL方法获取的图片必须通过revokeObjectURL方法进行回收。否则会占用浏览器系统资源。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: