Ajax学习(3)

来源:互联网 发布:linux进入图形界面 编辑:程序博客网 时间:2024/05/17 08:27

由于js中无法访问本地文件,因此用ajax上传文件无法实现,在早些时候的上传文件,都通过iframe或swf等方式来上传

而HTML5出现之后,可以实现ajax上传文件。

1、iframe下载文件

要达到的要求是,无刷新页面的上传文件,因此在提交数据表单的时候,将表单的target指向当前页面的iframe即可达到目的

前台测试代码 iframe_file.html

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Document</title><script type="text/javascript" src="http://libs.baidu.com/jquery/1.7.2/jquery.min.js"></script><script type="text/javascript">/*分析:1、捕捉表单提交的动作2、创建iframe3、把表单的target修改指向该iframe4、去掉该iframe */function ajaxUp() {var ifname = Math.random();$('<iframe name="'+ifname+'" width="0" height="0" frameBorder="0"></iframe>').appendTo($("body"));$('form:first').attr('target',ifname);$('#progress').html('<img src="jindutiao.jpg"/>');// return false;}</script><style type="text/css">p{border:1px solid gray;}</style></head><body><h1>iframe模拟ajax文件上传效果</h1><div id="progress"></div><form method="post" action="iframe_file.php" enctype="multipart/form-data" onsubmit="return ajaxUp()"><p><input type="file" name="pic"></input></p><p><input type="submit" name="提交"></input></p></form></body></html>

后台测试代码iframe_file.php

<?php sleep(3);if(empty($_FILES)){exit("no file");}$error = $_FILES['pic']['error']==0 ? 'succ':'fail';// echo $error;if($error == 0){echo "<script>parent.document.getElementById('progress').innerHTML='$error'</script>";}?>

2、FormData的使用

FormData是HTML5中的新特性,因此IE的老版本不支持,所以不考虑在内

FormData作为对象可以直接封装表单的dom对象

前台测试代码formData.html

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>formData</title><script type="text/javascript">/*formData打包表单数据*/function mySend(argument) {// body.../*表单数据*/var fm = document.getElementById("myForm");var fd = new FormData(fm);/*直接添加数据*/var fd2 = new FormData();fd2.append('username2',"ruiy");//xhr对象建立、链接、发送var xhr = new XMLHttpRequest();xhr.open("POST","formData.php",true);xhr.onreadystatechange = function() {if(this.readyState==4 && this.status==200){document.getElementById("debug").innerHTML = this.responseText;}}//xhr.send(fd);//发送表单数据xhr.send(fd2);//发送直接添加的数据}</script></head><body><form id="myForm">用户名<input type="text" name="username"/><br/>密码<input type="text" name="password"/><br/>邮箱<input type="text" name="email"/><br/>性别<input type="text" name="gender"/><br/><input type="button" name="send" value="发送" onclick="mySend()"></input></form><div id="debug"></div></body></html>

后台测试代码formData.php

<?php print_r($_POST); ?>

3、file上传

有了FormData,那么我们可以先通过dom获取文件对象,然后添加到FormData中,接着用HTTP POST的方式进行发送,在后台的$_FILES便可以接受到文件信息,然后通过move_uploaded_file来移动文件,但是要提前建立好要保存的路径的文件夹

前台测试代码fileApi.html

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>fileApi</title><script type="text/javascript">function selectFile() {var pic = document.getElementsByTagName("input")[0].files[0];//file为一个文件数组,files[0]为该pic文件//console.log(pic);var disp = document.getElementById("disp");//创建FormData对象var fd = new FormData();//把文件内容追加到FormData对象中fd.append('pic',pic);var tmpImg = document.createElement("img");tmpImg.src = window.URL.createObjectURL(pic);//把二进制文件对象转为浏览器可以显示的资源src,然后用img加载document.getElementsByTagName('body')[0].appendChild(tmpImg);//添加该img元素到浏览器中//xhr创建、链接、发送var xhr = new XMLHttpRequest();xhr.open("post","fileApi.php",true);xhr.onreadystatechange = function() {if(this.readyState==4 && this.status==200){disp.innerHTML = xhr.responseText;}}xhr.send(fd);/*var cont = "";cont += '文件名称:'+pic.name+'<br>';cont +="文件大小"+pic.size+'<br>';    disp.innerHTML = cont;*/}</script></head><body><input type="file" name="pic" onchange="selectFile()"></input><div id="disp"></div></body></html>

后台测试代码fileApi.php

<?php if(empty($_FILES)){//如果数组为空,则报错exit("no file");}if($_FILES['pic']['error']){//如果error值为1,则报错exit("fail");}move_uploaded_file($_FILES['pic']['tmp_name'],'upload/'.$_FILES['pic']['name']);// move_uploaded_file($_FILES['pic']['tmp_name'],'upload/'.$_FILES['pic']['name']);print_r($_FILES);?>

4、给上传文件加上进度条

XHR对象有要给属性为upload,绑定了onprogress的函数,通过该函数的事件,算出已加载和全部的比例,并通过css显示

<pre name="code" class="html"><!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>fileApi</title><script type="text/javascript">function selectFile() {var pic = document.getElementsByTagName("input")[0].files[0];//file为一个文件数组,files[0]为该pic文件//console.log(pic);var disp = document.getElementById("disp");//创建FormData对象var fd = new FormData();//把文件内容追加到FormData对象中fd.append('pic',pic);//显示上传的图片var tmpImg = document.createElement("img");tmpImg.src = window.URL.createObjectURL(pic);//把二进制文件对象转为浏览器可以显示的资源src,然后用img加载document.getElementsByTagName('body')[0].appendChild(tmpImg);//添加该img元素到浏览器中//xhr创建、链接、发送var xhr = new XMLHttpRequest();xhr.open("post","fileApi.php",true);xhr.onreadystatechange = function() {if(this.readyState==4 && this.status==200){//disp.innerHTML = xhr.responseText;//得到返回的文件信息}}/*显示进度条* HTML5中XHR对象有属性upload绑定了 上传过程 的监听事件* ev.total代表总的上传大小,ev.loaded代表意已上传的大小* ev.lengthComputable如果为true说明一次性上传,未分开* 然后通过百分比来显示**/xhr.upload.onprogress = function(ev){// alert("upload");// console.log(percent);if(ev.lengthComputable){//判断是否为一次性上传var percent = 100*ev.loaded/ev.total;document.getElementById("bar").style.width = percent+'%';document.getElementById("bar").innerHTML = parseInt(percent)+'%';}}xhr.send(fd);/*var cont = "";cont += '文件名称:'+pic.name+'<br>';cont +="文件大小"+pic.size+'<br>';    disp.innerHTML = cont;*/}</script><style type="text/css">#disp{width:500px;height:30px;border: 1px solid green;}#bar{width:0%;height: 100%;background: green;}</style></head><body><input type="file" name="pic" onchange="selectFile()"></input><div id="disp"><div id="bar"></div></div></body></html><span style="font-family: Arial, Helvetica, sans-serif;"></span>

实际上,还需要说明一点,

在HTML5中,ajax的跨域有了新的规则,能否跨域取决于对方的应答!

对方服务器如果愿意接受远程过来的Ajax,或某些指定域名的Ajax请求,,可以在header头信息中,添加Access-Control-Allow-Origin:*

5、文件分段上传

如果碰到需要分段上传的文件,那么就需要用到HTML5的新特性。File对象继承自Blob,Blob有函数为slice可用于切割文件,然后通过while循环分段上传即可。

注:在测试过程中,我试着上传了一个mp4格式的视频,出现了问题,首先要想上传成功,得设置成同步,然后每片的大小不能够太大,不然就无法成功,我每片上传2M的大小,这一点存疑。

照着这个思路走下去并没有错,唯一的问题是由于while循环一直在跑,并且Js中的进度条一直在随着每次循环改变,浏览器对页面做出的渲染反应是:等到循环结束才开始对进度条的css进行渲染,这导致了进度条无法实时进行更新。那么加上延迟呢,由于Js并没有诸如sleep之类的延迟函数,并且要多次访问File文件,所以采用了setIntervavl,进行定时访问,为了解决全局变量的问题,使用了Js函数的闭包。

测试代码bigFileApi.html

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>bigFile</title><script type="text/javascript">/** 用到的API* file->继承自->Blob* Blob有slice方法,可以截取二进制对象的一部分** 截取10M,然后上传* 判断文件有没有截取完毕* while(判断){*  截取;*  ajax上传;* } */var clock = null;function fire(){clock = window.setInterval(sendFile, 1000);}var sendFile = (function(){var fd = null;var xhr = new XMLHttpRequest(); var percent = 0; const LENGTH = 2*1024*1024;//设定片的大小为10Mvar start = 0;//声明和初始化开始var end = start+LENGTH;//声明和初始化结尾// var oFile = document.getElementsByName("upFile")[0].files[0];//获取文件对象var oFileChip = new Blob();//File对象继承自Blob对象,Blob对象中有一方法为slice,可截取文件对象中的某一段//var totalSize = oFile.size;//获取总长度,作为结束判断的条件// console.log(oFile);//以上都是初始化工作,为了达到实时刷新,使用定时器每隔1s来执行sendFile的动作//工作都是发生在页面加载之后,该匿名函数执行完成初始化工作,并将xml的操作放于内部函数中返回,赋于变量sendFire////当选择文件之后,会由定时器触发调用该函数var sending = false;//true表示文件正在上传,false表示文件不在上传状态return (function(){if(sending==true){return;//如果定时器再次访问的时候发现上一次文件尚未上传完毕,则返回等待下一次定时器的访问}var oFile = document.getElementsByName("upFile")[0].files[0];//获取文件对象if(start>oFile.size){clearInterval(clock);return;}oFileChip = oFile.slice(start, end);fd = new FormData();//console.log(oFileChip);fd.append('part',oFileChip);xhr.open("post","./bigFileApi.php",false);xhr.send(fd);start = end;end = start+LENGTH;sending = false;//表明上传完毕percent = parseInt(100*end/oFile.size);if(percent>100){percent = 100;}document.getElementById("bar").style.width = percent+"%";document.getElementById("bar").innerHTML = percent+"%";});})();// function sendFile() {// while(start<totalSize){// oFileChip = oFile.slice(start, end);//截取小片// fd = new FormData();// console.log(oFileChip);// fd.append('part',oFileChip);//包装成FormData// xhr = new XMLHttpRequest();// xhr.open("post","./bigFileApi.php",false);// //此处使用了同步的方式是为了避免传送文件片的时候造成的混乱// //但是若是用了同步,则在send的过程中onprogress无法响应,因此不能使用onprogress方式来表现进度条// xhr.upload.onprogress = function(ev){// var percent = 100*(start+ev.onloaded)/totalsize;// document.getElementById("bar").style.width = percent+'%';// document.getElementById("bar").innerHTML = parseInt(percent)+'%';// }// xhr.send(fd);//发送小片包装后的FormData// //用end显示进度条// percent = 100*end/totalSize;// alert(percent);// document.getElementById("bar").style.width = percent+'%';// document.getElementById("bar").innerHTML = parseInt(percent)+'%';// start = end;//设定下一片的开始// end = start+LENGTH;//设定下一片的末尾// }// }</script><style type="text/css">#progress{border:1px solid green;width: 500px;height: 30px;}#bar{background: green;width: 0%;height: 100%;}</style></head><body><h1>html5大文件切割上传</h1><div id='progress'><div id="bar"></div></div><input type="file" name="upFile" onchange="fire()"></input></body></html>


后天代码bigFileApi.php负责把传递过来的文件clips拼接起来,为此,首先要判断文件是否存在,如果不存在,则将临时文件存储至指定目录,如果存在,则对已经存在的文件进行追加。

<?php if(!file_exists('./upload/up.mp4')){move_uploaded_file($_FILES['part']['tmp_name'],'./upload/up.mp4');}else{file_put_contents('./upload/up.mp4',file_get_contents($_FILES['part']['tmp_name']),FILE_APPEND);}echo "ok"; ?>


1 0
原创粉丝点击