技术开发 频道

HTML5与Ajax强强联手 演绎文件上传

        【IT168 技术】在上一讲《玩转HTML5应用实战:灵活拖拉文件》文章中,我们学习了如何利用HTML5将文件拖拉到浏览器中,并读取出被拖拉文件的类型和其他文件相关信息。在本文中,将介绍如何利用Ajax及HTML5异步将文件上传到服务端。

  上传表单页面的设置

  先来看下上传表单页面的设置,代码如下:

<form id="upload" action="upload.php" method="POST" enctype="multipart/form-data">
<fieldset>
<legend>HTML File Upload</legend>
<input type="hidden" id="MAX_FILE_SIZE" name="MAX_FILE_SIZE" value="300000" />
<div>
    
<label for="fileselect">Files to upload:</label>
    
<input type="file" id="fileselect" name="fileselect[]" multiple="multiple" />
    
<div id="filedrag">or drop files here</div>
</div>
<div id="submitbutton">
    
<button type="submit">Upload Files</button>
</div>
</fieldset>
</form>

  这里,我们为表单的提交设置为upload.php,用来处理上传的文件,在表单中并且规定了上传的图片的大小不超过300K。

  上传的Javascript

  在对文件进行上传处理的Javascript中,代码如下:


// file selection
function FileSelectHandler(e) {
    
// cancel event and hover styling
    FileDragHover(e);
    
// fetch FileList object
    var files = e.target.files || e.dataTransfer.files;
    
// process all File objects
    for (var i = 0, f; f = files[i]; i++) {
        ParseFile(f);
        UploadFile(f);
    }
}

  在上个教程中,已经对ParseFile(f)进行了介绍,现在着重看下UploadFile这个方法的代码,代码如下:

function UploadFile(file) {

  var xhr
= new XMLHttpRequest();

  
if (xhr.upload && file.type == "image/jpeg" && file.size <= $id("MAX_FILE_SIZE").value) {

  
// start upload

  xhr.open(
"POST", $id("upload").action, true);

  xhr.setRequestHeader(
"X_FILENAME", file.name);

  xhr.send(file);

  }

  }

  在上面的代码中,使用了目前只有在FireFox和Chrome中才支持的XmlHttpRequest2对象,XmlHttpRequest2是对原先大家熟悉的xmlhttprequest的加强,目前还没最后定案,可以参考http://dev.w3.org/2006/webapi/XMLHttpRequest-2/的描述。在上面的代码中,首先是判断了上传文件的类型是否为图片文件以及大小是否符合要求,如果符合要求的话,则调用send方法发送文件到服务端,并且这里设置了HTTP文件头X_FILENAME为上传的文件名。

  在PHP服务端的代码中,首先通过HTTP头来判断是否通过AJAX上传还是普通的表单上传。

 $fn = (isset($_SERVER['HTTP_X_FILENAME']) ? $_SERVER['HTTP_X_FILENAME'] : false);

  
if ($fn) {

  
// AJAX调用

  file_put_contents(

  
'uploads/' . $fn,

  file_get_contents(
'php://input')

  );

  echo
"$fn uploaded";

  exit();

  }

  如果$fn中设置了值,则调用使用file_put_contents方法,将文件复制到uploads文件夹,而如果是通过普通表单的上传,则作如下判断:

 else {

  $files
= $_FILES['fileselect'];

  foreach ($files[
'error'] as $id => $err) {

  
if ($err == UPLOAD_ERR_OK) {

  $fn
= $files['name'][$id];

  move_uploaded_file(

  $files[
'tmp_name'][$id],

  
'uploads/' . $fn

  );

  echo
"

  File $fn uploaded.

  
";

  }


  }

  }

  以上这段代码即是针对普通的表单上传代码。

  显示上传进度条

  接下来,为了方便用户,需要显示一个上传的进度条。在HTML4的时代里,显示进度条是比较麻烦的,需要其他一些Javascript技巧。在HTML5中,出现了进度条的属性功能(目前在FireFox和Chrome中的XmlHttpRequest2)中对其进行了支持。

  HTML5中的进度条属性中,有两个分别是:value和Max。其中value显示当前进度条的值得,Max的值为定义进度条最大的值。很不幸的是,目前HTML5标准中对进度条的定义中,缺乏样式上的定义,因此只能靠开发者对其进行美化,定义样式如下:

 #progress p

  {

  display: block;

  width: 240px;

  padding: 2px 5px;

  margin: 2px
0;

  border: 1px inset #
446;

  border
-radius: 5px;

  }

  其中,设计了一张进度条,宽度设计为500px,其中250px为绿色部分,即已读取部分,右边的250px部分设置为透明。

  这里,我们根据上传的进度,动态设置其样式,定义为“X% 0″,其中X表示剩余多少部分是还没上传完成的,比如:“background-position: 100% 0表示刚开始上传,还没完成任何部分,background-position: 0% 0表示0%剩余,即已经全部完成上传,

  background-position: 30% 0″表示还有30%还没完成上传。

  另外,还设计了当上传成功或失败时,所需要的样式,如下所示:

 #progress p.success

  {

  background: #0c0 none
0 0 no-repeat;

  }

  #progress p.failed

  {

  background: #c00 none
0 0 no-repeat;

  }

 接下来修改之前的uploadfile()方法,添加如下代码:

function UploadFile(file) {

  var xhr
= new XMLHttpRequest();

  
if (xhr.upload && file.type == "image/jpeg" && file.size <= $id("MAX_FILE_SIZE").value) {

  var o
= $id("progress");

  var progress
= o.appendChild(document.createElement("p"));

  progress.appendChild(document.createTextNode(
"upload " + file.name));

  这里增加了关于进度条的样式,并添加了文字说明,说明上传的文件名。回忆一下,

  这里的var o = $id("progress");实际上是找到了页面中设定的HTML5中的progress标签元素。

  接下来,我们在xmlHttpRequest2的upload事件中增加关于上传进度的计算,如下代码:

 xhr.upload.addEventListener("progress", function(e) {

  var pc
= parseInt(100 - (e.loaded / e.total * 100));

  progress.style.backgroundPosition
= pc + "% 0";

  },

  其中PC为剩余的上传进度,并且赋值给progress的CSS样式。最后,如果你熟AJAX,则知道通过onreadystatechange去判断是否文件上传完成,代码如下:

xhr.onreadystatechange = function(e) {

  
if (xhr.readyState == 4) {

  progress.className
= (xhr.status == 200 ? "success" : "failure");

  }

  };

  同样,通过readState去判断是否上传成功,并设置相关的CSS样式。至于其他部分代码,则不需要再修改了。

  现在,一个带进度条的上传文件的例子就做好了,具体的代码可以通过

  http://blogs.sitepointstatic.com/examples/tech/filedrag/3/filedrag3.zip下载。

  小结

  在本系列的两个教程中,指导读者认识了HTML5中新的文件API接口,它允许用户从本地机器的文件夹中直接拖拉文件到浏览器中,并讲解了如何 分析选中上传文件的文件信息,最后还利用了HTML5中的新特性xmlHttpRequest 2及进度条的标签,实现了一个带进度条的上传功能。

0
相关文章