HTML5实现文件上传及代码详解

此笔记通过一个上传代码的实例,详细讲解了通过HTML5 API实现文件上传的步骤。其中包含文件上传的相关知识点,File对象、FormData对象、HTML5的进度事件及FileReader接口。文末有详细的上传代码。

XMLHttpRequest Level 2

在HTML5标准中,XMLHttpRequest对象被重新定义,被称为“XMLHttpRequest Level 2”,与老版本的XMLHttpRequest对象相比,它有以下几个新特性:

  • 可以设置HTTP请求的时限。
  • 可以使用FormData对象管理表单数据。
  • 可以上传文件。
  • 可以请求不同域名下的数据(跨域请求)。
  • 可以获取服务器端的二进制数据。
  • 可以获得数据传输的进度信息。

事件

文件上传的HTML结构

<form action="upload.php" method="post" enctype="multipart/form-data">

<input data-loading-text="处理中..." id="fileToUpload"
						   class="btn btn-info file-info"
                           name="myfile"
                           type="file"
                           accept=".xlc,.xlm,.xls,.xlt,.xlw,.xlsx">	

其中,在<form>标签里应注明enctype类型为multipart/form-data

enctype 属性规定在发送到服务器之前应该如何对表单数据进行编码。

input表单应修改type类型file

accept属性

指定浏览器接受的文件类型,多个属性逗号分隔

accept=”image/*”
accept=”application/pdf”
accept=”audio/x-mpeg”
accept=”text/html”
accept=”video/x-mpeg2″

样式改进

原生的file表单样式太丑,我们可以让其透明度为0,覆盖在我们的按钮上,点击按钮时,实际上点击的是file元素。

使用label元素与file控件关联

<label class="ui_button ui_button_primary" for="xFile">上传文件</label>
<form><input type="file" id="xFile" style="position:absolute;clip:rect(0 0 0 0);"></form>

效果:

File对象

上传表单有单独的file对象:

 var file = document.getElementById('fileToUpload').files[0];
 console.log(file);

其中,
– name – 文件名(不包含路径)
– type – 文件的MIME类型(小写)
– size – 文件的尺寸(单位为字节)

通过这三个内容,我们可以控制用户上传的文件大小和文件类型。

FormData

XMLHttpRequest 2 定义了FormData对象,通过 JavaScript 用一些键值对来模拟一系列表单控件。我们还可以使用 XMLHttpRequestsend()方法来异步的提交表单。与普通的 Ajax 相比,使用FormData的最大优点就是我们可以异步上传二进制文件

可以先创建一个空的 FormData对象,然后使用 append()方法向该对象里添加字段:
append()方法接受两个参数:键和值,分别对应表单字段的名字和值。

var myForm = new FormData(),
    fileInputElement = document.getElementById('myFormInput');

myForm.append("name", "Shady");
myForm.append("userfile", fileInputElement.files[0]); //

创建了FormData实例后,可以将它直接传给XHRsend()方法。

var xhr = new XMLHttpRequest();
xhr.open("POST", "formData.php");
xhr.send(myForm); 

使用HTML表单来初始化一个FormData对象

可以用一个已有的 form元素来初始化FormData对象,只需要把这个form元素作为参数传入FormData构造函数即可:

var newFormData = new FormData(someFormElement);

例如:

var formElement = document.getElementById("myFormElement");
var xhr = new XMLHttpRequest();
xhr.open("POST", "submitform.php"); 
xhr.send(new FormData(formElement));

你还可以在已有表单数据的基础上,用append()继续添加新的键值对。

使用 jQuery 来发送 FormData

可以使用 jQuery 来发送 FormData,但必须要正确的设置相关选项:

var file = $('#test-input')[0].files[0];
var formData = new FormData();

formData.append('file', file);

$.ajax({
  url: "stash.php",
  type: "POST",
  data: formData,
  processData: false,  // 告诉jQuery不要去处理发送的数据
  contentType: false   // 告诉jQuery不要去设置Content-Type请求头
});

HTML5的进度事件

上传需要用到进度条时,可以使用HTML5的进度事件。

HTML5当中新增了一个进度事件(Progress Events),这个事件为我们提供了以下信息:

total – 文件大小
loaded – 已上传的大小
lengthComputable – 进度是否可计算

 var xhr = new XMLHttpRequest();
  xhr.upload.addEventListener("progress", uploadProgress, false);

function uploadProgress(evt) {
  if (evt.lengthComputable) {
    var percentComplete = Math.round(evt.loaded * 100 / evt.total);
    document.getElementById('progressNumber').innerHTML = percentComplete.toString() + '%';
  }
  else {
    document.getElementById('progressNumber').innerHTML = 'unable to compute';
  }
}

*上传的完整代码

HTML:

<body>
  <form id="form1" enctype="multipart/form-data" method="post" action="upload.php">
    <div class="row">
      <label for="fileToUpload">Select a File to Upload</label>
      <input type="file" name="fileToUpload" id="fileToUpload" onchange="fileSelected();"/>
    </div>
    <div id="fileName"></div>
    <div id="fileSize"></div>
    <div id="fileType"></div>
    <div class="row">
      <input type="button" onclick="uploadFile()" value="Upload" />
    </div>
    <div id="progressNumber"></div>
  </form>
</body>

JavaScript:

 function fileSelected() {
  var file = document.getElementById('fileToUpload').files[0];
  if (file) {
    var fileSize = 0;
    if (file.size > 1024 * 1024)
      fileSize = (Math.round(file.size * 100 / (1024 * 1024)) / 100).toString() + 'MB';
    else
      fileSize = (Math.round(file.size * 100 / 1024) / 100).toString() + 'KB';

    document.getElementById('fileName').innerHTML = 'Name: ' + file.name;
    document.getElementById('fileSize').innerHTML = 'Size: ' + fileSize;
    document.getElementById('fileType').innerHTML = 'Type: ' + file.type;
  }
}

function uploadFile() {
  var fd = new FormData();
  fd.append("fileToUpload", document.getElementById('fileToUpload').files[0]);
  var xhr = new XMLHttpRequest();
  xhr.upload.addEventListener("progress", uploadProgress, false);
  xhr.addEventListener("load", uploadComplete, false);
  xhr.addEventListener("error", uploadFailed, false);
  xhr.addEventListener("abort", uploadCanceled, false);
  xhr.open("POST", "UploadMinimal.aspx");
  xhr.send(fd);
}

function uploadProgress(evt) {
  if (evt.lengthComputable) {
    var percentComplete = Math.round(evt.loaded * 100 / evt.total);
    document.getElementById('progressNumber').innerHTML = percentComplete.toString() + '%';
  }
  else {
    document.getElementById('progressNumber').innerHTML = 'unable to compute';
  }
}

function uploadComplete(evt) {
  /* This event is raised when the server send back a response */
  alert(evt.target.responseText);
}

function uploadFailed(evt) {
  alert("There was an error attempting to upload the file.");
}

function uploadCanceled(evt) {
  alert("The upload has been canceled by the user or the browser dropped the connection.");
}

FileReader接口

实际上在fileSelected函数里可以使用 FileReader接口,new FileReader()的方法创建一个文件读取对象

FileReader接口有4个方法,其中3个用来读取文件,另一个用来中断读取。无论读取成功或失败,方法并不会返回读取结果,这一结果存储在result属性中。

FileReader接口事件

FileReader使用

实例: 通过FileReader上传图片

var result=document.getElementById("result");  
var file=document.getElementById("file");  

//判断浏览器是否支持FileReader接口  
if(typeof FileReader == 'undefined'){  
    result.InnerHTML="<p>你的浏览器不支持FileReader接口!</p>";  
    //使选择控件不可操作  
    file.setAttribute("disabled","disabled");  
}  

function readAsDataURL(){  
    //检验是否为图像文件  
    var file = document.getElementById("file").files[0];  
    if(!/image\/\w+/.test(file.type)){  
        alert("看清楚,这个需要图片!");  
        return false;  
    }  
    var reader = new FileReader();  
    //将文件以Data URL形式读入页面  
    reader.readAsDataURL(file);  
    reader.onload=function(e){  
        var result=document.getElementById("result");  
        //显示文件  
        result.innerHTML='<img src="' + this.result +'" alt="" />';  
    }  
}  

function readAsBinaryString(){  
    var file = document.getElementById("file").files[0];  
    var reader = new FileReader();  
    //将文件以二进制形式读入页面  
    reader.readAsBinaryString(file);  
    reader.onload=function(f){  
        var result=document.getElementById("result");  
        //显示文件  
        result.innerHTML=this.result;  
    }  
}  

function readAsText(){  
    var file = document.getElementById("file").files[0];  
    var reader = new FileReader();  
    //将文件以文本形式读入页面  
    reader.readAsText(file);  
    reader.onload=function(f){  
        var result=document.getElementById("result");  
        //显示文件  
        result.innerHTML=this.result;  
    }  
}  
<p>  
    <label>请选择一个文件:</label>  
    <input type="file" id="file" />  
    <input type="button" value="读取图像" onclick="readAsDataURL()" />  
    <input type="button" value="读取二进制数据" onclick="readAsBinaryString()" />  
    <input type="button" value="读取文本文件" onclick="readAsText()" />  
</p>  
<div id="result" name="result"></div>  

发表评论

电子邮件地址不会被公开。 必填项已用*标注