(PS:英文原文可以看 《Uploading Files with AJAX》)。
1.在demo中我们要实现的功能
- 异步上传文件(支持多选上传)
- 可以即时预览图片
2.通过这篇教程你将学会什么?
- ajax异步文件上传的核心原理
- 新的文件API:FileReader对象的用法;
- FormData对象的用法(这是XMLHttpRequest2的内容)。
很遗憾的是IE对FileReader和FormData并不支持(包括IE9),所以文中的方案有兼容性问题,想要实现全兼容的文件上传(包括图片预览),还需要其他技巧,以后讲解明河完成的异步上传组件时会说明。
(PS:Opera目前不支持FormData对象,请在firefox和chrome下浏览demo。)
3.构建图片上传表单
- <form method="post" enctype="multipart/form-data" action="upload.php">
- <input type="file" name="images" id="images" multiple />
- <button type="submit" id="btn">Upload Files!</button>
- </form>
想要实现异步文件上传的第一个关键步骤,给form增加enctype=”multipart/form-data”属性,这个属性非常关键,缺少这个属性,将直接提交表单。
action属性指向处理文件上传数据的服务器端路径。
多选上传的关键是在上传框上加multiple属性。
4.upload.php
我们先来看服务器端处理文件脚本:
- <?php
- foreach ($_FILES["images"]["error"] as $key => $error) {
- if ($error == UPLOAD_ERR_OK) {
- $name = $_FILES["images"]["name"][$key];
- move_uploaded_file( $_FILES["images"]["tmp_name"][$key], "uploads/" . $_FILES['images']['name'][$key]);
- }
- }
- echo "<h2>文件成功上传!</h2>";
这段php脚本做了非常多的简化,比如缺少文件大小限制、文件去重、用户限制等一系列安全处理。
$_FILES这个关联数组存放着文件数据,是处理的关键,有不清楚的朋友可以看php手册,这里不再累述,毕竟不是本文讲解重点。
5.监听上传框的change事件
- var input = document.getElementById("images");
- input.addEventListener("change", function (evt) {
- var files = this.files;
- })
留意这里的this.files,files数组将存储你上传的文件信息,即使只上传1张图片,也是数组形式出现。
6.利用FileReader将图片显示到页面上
关于FileReader,w3c有非常详细的说明,传送门点此。
- //遍历文件
- for ( ; i < len; i++ ) {
- file = this.files[i];
- //文件类型为图片
- if (!!file.type.match(/image.*/)) {
- //浏览器支持FileReader对象
- if ( window.FileReader ) {
- reader = new FileReader();
- //监听文件读取结束后事件
- reader.onloadend = function (e) {
- //将图片添加到显示列表
- showUploadedItem(e.target.result, file.fileName);
- };
- //读取文件
- reader.readAsDataURL(file);
- }
- //将文件数据添加到FormData对象内
- if (formdata) {
- formdata.append("images[]", file);
- }
- }
- }
首先需要判断下文件类型,file.type.match(/image.*/),如果是图片,file.type值会类似“image/jpeg”的形式。
接下来实例化FileReader读取文件。
- reader = new FileReader();
- //监听文件读取结束后事件
- reader.onloadend = function (e) {
- //将图片添加到显示列表
- showUploadedItem(e.target.result, file.fileName);
- };
- //读取文件
- reader.readAsDataURL(file);
FileReader有6个事件( onloadstart、onprogress、onload、onabort、 onerror、onloadend),onloadend监听读取完毕事件,我们需要读取结束后把图片打印到页面。
留意e.target.result,result包含图片数据
最后来看下showUploadedItem函数:
- //显示上传图片
- function showUploadedItem (source) {
- var list = document.getElementById("image-list"),
- li = document.createElement("li"),
- img = document.createElement("img");
- img.src = source;
- li.appendChild(img);
- list.appendChild(li);
- }
非常简单,将img元素添加到li元素,然后li添加到ul即可。
7.ajax发送FormData数据
- //遍历文件
- for ( ; i < len; i++ ) {
- file = this.files[i];
- //将文件数据添加到FormData对象内
- if (formdata) {
- formdata.append("images[]", file);
- }
- }
将文件信息添加到formdata。
- //发送ajax请求,存储文件(传递FormData对象过去)
- if (formdata) {
- $.ajax({
- url: "upload.php",
- type: "POST",
- data: formdata,
- processData: false,
- contentType: false,
- success: function (res) {
- //将上传成功后的提示打印到页面
- document.getElementById("response").innerHTML = res;
- }
- });
- }
发送异步请求将数据传给upload.php处理。这里使用jquery的ajax方法。