HTML5的File API
说到File API,比如有意思就是图片上传了。国外有一个网站叫min.us 用户只需要把图片拖到网页面中,然后自己进行排序就OK了,很方便。
下面是关于它的一段介绍视频:
目前网页上传分为三种:
1、form提交
2、flash上传
3、插件上传
各有利弊,fomr提交就是没进度条,不太好取消。flash比较难搞的就是在非ie中浏览器认为flash是新窗口会话,当前网页的cookie无法传递到flash上传工具中,而针对这个一般就是用JS把当前页面中的cookie通过flash再传给后台,而对于一个后台如果使用了统一验证身份的接口那可能会有点麻烦。第三种优势很明显,比如适合如QQ空间这样用户需要大批量上传图片的,缺点也显而易见:跨浏览器上存在问题。而HTML5中的FileReader对象与as3中的很像,只不过目前as3中的方法比这个多(有兴趣可以自己去看看adobe的lives docs,对比一下两者的区别与共同点)。
讲了这么多,回到正题:File API,拿图片上传为例(File、FileReader):
1、首先,如何控制用户单选、多选。as3中是两个不同的对象:FileReference、FileReferenceList,在as3中可以使用FileFilter过滤只允许选择的上传文件。as3中需要使用flash player 10+才支持本地预览,而且图片不易过大。
HTML5中允许选择多个文件:
<input type="file" multiple>
只允许上传一个文件:
<input type="file" single>
2、如何让用户只能上传指定的文件格式,如上传图片组件只允许png、jpg、gif、jpeg、bmp后缀格式的图片。
我尝试着去寻找HTML5中是否也如as3中可以让开发者自定义过滤选择文件呢,结果被我找到了http://en.wikipedia.org/wiki/File_select 添加一个属性就好了accept="image/gif,image/png"
默认为“自定义文件”,如果我选择“所有文件”,所有的文件都将显示出来。
3、上传文件
这里遇到一个问题,如何获取ajax发送过去的图片信息。因为在ajax中使用的是setRequestHeader将图片信息传给后台,因为使用的nginx,无法直接获取
自定义的http-header,就修改了fastcgi-params,加了三项:
关于定义的配置规则,可以参考这一篇文章:nginx下php获取自定义请求头参数的方法
搜索了很多关于html5 upload的例子,有人用.net、ruby写了,但没有找到用php写的(有是有,不过是使用提交form至iframe的方法,不符合这里的需求),比如这个:http://valums.com/ajax-upload/ http://www.atwebresults.com/php_ajax_image_upload/
查了很久(已经很晚了,明天还得上班就不折腾了),暂时放弃php的部分,有空再写完整的例子,重点是看File、FileReader的方法(实现了本地预览的功能)
本地运行的效果:
有空再把完整的demo提供下载(暂时缺省后台php保存文件的方法),html的源码:
<!DOCTYPE html>
<html>
<head>
<title>File API</title>
<meta charset="utf-8">
<style>
#drop-area {
height: 50px;
line-height:50px;
text-align: center;
border: 2px dashed #ddd;
padding: 10px;
margin-bottom: 2em;
}
#drop-area .drop-instructions {
display: block;
height: 30px;
}
#drop-area .drop-over {
display: none;
font-size: 25px;
height: 30px;
}
#drop-area.over {
background: #ffffa2;
border: 2px dashed #000;
}
#drop-area.over .drop-instructions {
display: none;
}
#drop-area.over .drop-over {
display: block;
}
#drop-area.over .drop-over {
display: block;
font-size: 25px;
}
#file-list {
list-style: none;
margin-bottom: 3em;
}
#file-list li {
border-bottom: 1px solid #000;
margin-bottom: 0.5em;
padding-bottom: 0.5em;
}
#file-list li.no-items {
border-bottom: none;
}
#file-list div {
margin-bottom: 0.5em;
}
#file-list li img {
max-width: 400px;
}
#file-list .progress-bar-container {
width: 400px;
height: 10px;
border: 1px solid #555;
margin-bottom: 20px;
}
#file-list .progress-bar-container.uploaded {
height: auto;
border: none;
}
#file-list .progress-bar {
width: 0;
height: 10px;
font-weight: bold;
background: #6787e3;
}
#file-list .progress-bar-container.uploaded .progress-bar{
display: inline-block;
width: auto;
color: #6db508;
background: transparent;
}
</style>
</head>
<body>
<section id="main-content">
<h2>文件上传</h2>
<h3>请选择文件</h3>
<p>
<input id="files-upload" type="file" multiple accept="*.*" name="file">
</p>
<p id="drop-area">
<span class="drop-instructions">将文件拖拽到这里</span>
<span class="drop-over">Drop files here!</span>
</p>
<ul id="file-list">
<li class="no-items"> </li>
</ul>
</section>
<script>1:
2: !(function () {3: var filesUpload = document.getElementById("files-upload"),4: dropArea = document.getElementById("drop-area"),5: fileList = document.getElementById("file-list");6:
7: function uploadFile (file) {8: var li = document.createElement("li"),9: div = document.createElement("div"),10: img,
11: progressBarContainer = document.createElement("div"),12: progressBar = document.createElement("div"),13: reader,
14: xhr,
15: fileInfo;
16:
17: li.appendChild(div);
18:
19: progressBarContainer.className = "progress-bar-container";20: progressBar.className = "progress-bar";21: progressBarContainer.appendChild(progressBar);
22: li.appendChild(progressBarContainer);
23:
24: /*25: If the file is an image and the web browser supports FileReader,26: present a preview in the file list27: */28: if (typeof FileReader !== "undefined" && (/image/i).test(file.type)) {29: img = document.createElement("img");30: li.appendChild(img);
31: reader = new FileReader();32: reader.onload = (function (theImg) {33: return function (evt) {34: theImg.src = evt.target.result;
35: };
36: }(img));
37: reader.readAsDataURL(file);
38: }
39:
40: // Uploading - for Firefox, Google Chrome and Safari41: xhr = new XMLHttpRequest();42:
43: // Update progress bar44: xhr.upload.addEventListener("progress", function (evt) {45: if (evt.lengthComputable) {46: progressBar.style.width = (evt.loaded / evt.total) * 100 + "%";47: }
48: else {49: // No data to calculate on50: }
51: }, false);52:
53: // File uploaded54: xhr.addEventListener("load", function () {55: progressBarContainer.className += " uploaded";56: progressBar.innerHTML = "Loaded!";57: }, false);58:
59: xhr.open("post", "upload/upload.php", true);60:
61: // Set appropriate headers62: xhr.setRequestHeader("Content-Type", "multipart/form-data");63: xhr.setRequestHeader("X-File-Name", file.fileName);64: xhr.setRequestHeader("X-File-Size", file.fileSize);65: xhr.setRequestHeader("X-File-Type", file.type);66:
67:
68: xhr.onreadystatechange = function() {69: if (xhr.readyState === 4) {70: if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {71: alert(xhr.responseText);
72: xhr = null;73: }
74: }
75: }
76:
77: // Send the file (doh)78: if ("getAsBinary" in file) {79: //FF 3.5+80: xhr.sendAsBinary(file.getAsBinary());
81: } else {82: xhr.send(file);
83: }
84:
85:
86: // Present file info and append it to the list of files87: fileInfo = "<div><strong>Name:</strong> " + file.name + "</div>";88: fileInfo += "<div><strong>Size:</strong> " + parseInt(file.size / 1024, 10) + " kb</div>";89: fileInfo += "<div><strong>Type:</strong> " + file.type + "</div>";90: div.innerHTML = fileInfo;
91:
92: fileList.appendChild(li);
93: }
94:
95: function traverseFiles (files) {96: if (typeof files !== "undefined") {97: for (var i=0, l=files.length; i<l; i++) {98: uploadFile(files[i]);
99: }
100: }
101: else {102: fileList.innerHTML = "No support for the File API in this web browser";103: }
104: }
105:
106: filesUpload.addEventListener("change", function () {107: traverseFiles(this.files);108: }, false);109:
110: dropArea.addEventListener("dragleave", function (evt) {111: var target = evt.target;112:
113: if (target && target === dropArea) {114: this.className = "";115: }
116: evt.preventDefault();
117: evt.stopPropagation();
118: }, false);119:
120: dropArea.addEventListener("dragenter", function (evt) {121: this.className = "over";122: evt.preventDefault();
123: evt.stopPropagation();
124: }, false);125:
126: dropArea.addEventListener("dragover", function (evt) {127: evt.preventDefault();
128: evt.stopPropagation();
129: }, false);130:
131: dropArea.addEventListener("drop", function (evt) {132: traverseFiles(evt.dataTransfer.files);
133: this.className = "";134: evt.preventDefault();
135: evt.stopPropagation();
136: }, false);137: })();
</script>
</body>
</html>