HTML5托拽上传(XMLHttpRequest和Google Gears)
HTML5的拖拽上传功能可拆分为两个部分实现,一个是对象的拖拽功能,另一个是上传功能。拖拽功能的实现基于HTML5 DOM对象的拖拽事件 ,FF3.6+和Chrome7+都实现了该功能,所以不用做特别的兼容,代码如下:
而HTML5的文件传输功能则是基于两套实现方式:
firefox:
fileReader.readAsBinaryString 读取二进制串
XMLHttpRequest.sendAsBinary 以二进制的格式发送给服务器端(真给力)
chrome:
gears API
因为XMLHttpRequest.sendAsBinary目前还没有被w3c列为标准,所以只能在Firefox中私有地使用。
以下是简单封装的两个浏览器的上传类
两种上传方式都是用的基于表单的文件传输协议 RFC-1867 (RFC-1867 中文版)。
拖拽功能代码
var uploadZone=$("uploadZone"),
iptFile,
file,
ffUpload=new FirefoxFileUpload("http://localhost/upload/a.php");
//chromeUpload=new ChromeFileUpload("http://localhost/upload/a.php");
function focus(state){
uploadZone.style.backgroundColor=state?"#f0ab0c":"";
}
uploadZone.addEventListener("dragenter",function(e){
focus(true);
e.stopPropagation();
e.preventDefault();
},false);
uploadZone.addEventListener("dragleave",function(e){
focus(false);
},false);
uploadZone.addEventListener("dragover",function(e){
e.stopPropagation();
e.preventDefault();
},false);
uploadZone.addEventListener("drop",function(e){
e.stopPropagation();
e.preventDefault();
focus(false);
//Firefox上传
ffUpload.xhr.upload.onprogress=function(e){
var w=$("pgBorder").offsetWidth;
$("progress").style.width=e.loaded/e.total*w+"px";
};
ffUpload.xhr.upload.onload=function(){
$("progress").style.width=$("pgBorder").offsetWidth+"px";
};
ffUpload.upload(ffUpload.getFile(e));
//Chrome上传
// chromeUpload.xhr.upload.onprogress=function(e){
// console.log(e.loaded/e.total*100+"%");
// };
// chromeUpload.upload(chromeUpload.getFile(e));
},false);
iptFile,
file,
ffUpload=new FirefoxFileUpload("http://localhost/upload/a.php");
//chromeUpload=new ChromeFileUpload("http://localhost/upload/a.php");
function focus(state){
uploadZone.style.backgroundColor=state?"#f0ab0c":"";
}
uploadZone.addEventListener("dragenter",function(e){
focus(true);
e.stopPropagation();
e.preventDefault();
},false);
uploadZone.addEventListener("dragleave",function(e){
focus(false);
},false);
uploadZone.addEventListener("dragover",function(e){
e.stopPropagation();
e.preventDefault();
},false);
uploadZone.addEventListener("drop",function(e){
e.stopPropagation();
e.preventDefault();
focus(false);
//Firefox上传
ffUpload.xhr.upload.onprogress=function(e){
var w=$("pgBorder").offsetWidth;
$("progress").style.width=e.loaded/e.total*w+"px";
};
ffUpload.xhr.upload.onload=function(){
$("progress").style.width=$("pgBorder").offsetWidth+"px";
};
ffUpload.upload(ffUpload.getFile(e));
//Chrome上传
// chromeUpload.xhr.upload.onprogress=function(e){
// console.log(e.loaded/e.total*100+"%");
// };
// chromeUpload.upload(chromeUpload.getFile(e));
},false);
而HTML5的文件传输功能则是基于两套实现方式:
firefox:
fileReader.readAsBinaryString 读取二进制串
XMLHttpRequest.sendAsBinary 以二进制的格式发送给服务器端(真给力)
chrome:
gears API
因为XMLHttpRequest.sendAsBinary目前还没有被w3c列为标准,所以只能在Firefox中私有地使用。
以下是简单封装的两个浏览器的上传类
Firefox 上传类
var FirefoxFileUpload=function(url,dataName){
this.xhr=new XMLHttpRequest();
this.__file=null;
this.__fileReader=new FileReader();
this.__url=url;
this.__dataName=dataName || "FileData";
this.__initReader();
};
FirefoxFileUpload.prototype={
upload:function(file){
if(!file){
return;
}
this.__file=file;
this.__fileReader.readAsBinaryString(this.__file);
},
getFile:function(e){
return e.dataTransfer.files[0];
},
__send:function(){
var xhr=this.xhr,
boundary="----------BOUNDARY"+(new Date()).getTime(),
body=this.__getBody(this.__fileReader.result,boundary);
xhr.open("post",this.__url,true);
xhr.setRequestHeader("Content-Type","multipart/form-data, boundary="+boundary);
xhr.setRequestHeader("Content-Length",this.__file.size);
xhr.sendAsBinary(body);
},
__initReader:function(){
var me=this;
this.__fileReader.addEventListener("load",function(){
me.__send();
},false);
},
__getBody:function(readerResult,boundary){
return ['--',boundary,'\r\n',
'content-disposition: form-data; name="',this.__dataName,'"; filename="',encodeURI(this.__file.name),'"\r\n',
'Content-Type: ',this.__file.type,'\r\n\r\n',
readerResult,"\r\n",
'--',boundary,'--\r\n'
].join("");
}
};
this.xhr=new XMLHttpRequest();
this.__file=null;
this.__fileReader=new FileReader();
this.__url=url;
this.__dataName=dataName || "FileData";
this.__initReader();
};
FirefoxFileUpload.prototype={
upload:function(file){
if(!file){
return;
}
this.__file=file;
this.__fileReader.readAsBinaryString(this.__file);
},
getFile:function(e){
return e.dataTransfer.files[0];
},
__send:function(){
var xhr=this.xhr,
boundary="----------BOUNDARY"+(new Date()).getTime(),
body=this.__getBody(this.__fileReader.result,boundary);
xhr.open("post",this.__url,true);
xhr.setRequestHeader("Content-Type","multipart/form-data, boundary="+boundary);
xhr.setRequestHeader("Content-Length",this.__file.size);
xhr.sendAsBinary(body);
},
__initReader:function(){
var me=this;
this.__fileReader.addEventListener("load",function(){
me.__send();
},false);
},
__getBody:function(readerResult,boundary){
return ['--',boundary,'\r\n',
'content-disposition: form-data; name="',this.__dataName,'"; filename="',encodeURI(this.__file.name),'"\r\n',
'Content-Type: ',this.__file.type,'\r\n\r\n',
readerResult,"\r\n",
'--',boundary,'--\r\n'
].join("");
}
};
Chrome 上传类
var ChromeFileUpload=function(url,dataName){
this.xhr=google.gears.factory.create("beta.httprequest");
this.__url=url;
this.__file=null;
this.__builder=google.gears.factory.create("beta.blobbuilder");
this.__dataName=dataName || "FileData";
};
ChromeFileUpload.prototype={
upload:function(file){
this.__file=file;
this.__send();
},
getFile:function(e){
var desktop=google.gears.factory.create("beta.desktop");
return desktop.getDragData(e,"application/x-gears-files").files[0];
},
__send:function(){
var xhr=this.xhr,
boundary="----------BOUNDARY"+(new Date()).getTime();
xhr.open("post",this.__url,true);
xhr.setRequestHeader("Content-Type","multipart/form-data, boundary="+boundary);
this.__updateBuilder(boundary);
xhr.send(this.__builder.getAsBlob());
},
__updateBuilder:function(boundary){
var bdr=this.__builder;
bdr.append(['--',boundary,'\r\n',
'content-disposition: form-data; name="',this.__dataName,'"; filename="',encodeURI(this.__file.name),'"\r\n',
'Content-Type: ',this.__file.type,'\r\n\r\n'].join(""));
bdr.append(this.__file.blob);
bdr.append(["\r\n",
'--',boundary,'--\r\n'
].join(""));
}
};
this.xhr=google.gears.factory.create("beta.httprequest");
this.__url=url;
this.__file=null;
this.__builder=google.gears.factory.create("beta.blobbuilder");
this.__dataName=dataName || "FileData";
};
ChromeFileUpload.prototype={
upload:function(file){
this.__file=file;
this.__send();
},
getFile:function(e){
var desktop=google.gears.factory.create("beta.desktop");
return desktop.getDragData(e,"application/x-gears-files").files[0];
},
__send:function(){
var xhr=this.xhr,
boundary="----------BOUNDARY"+(new Date()).getTime();
xhr.open("post",this.__url,true);
xhr.setRequestHeader("Content-Type","multipart/form-data, boundary="+boundary);
this.__updateBuilder(boundary);
xhr.send(this.__builder.getAsBlob());
},
__updateBuilder:function(boundary){
var bdr=this.__builder;
bdr.append(['--',boundary,'\r\n',
'content-disposition: form-data; name="',this.__dataName,'"; filename="',encodeURI(this.__file.name),'"\r\n',
'Content-Type: ',this.__file.type,'\r\n\r\n'].join(""));
bdr.append(this.__file.blob);
bdr.append(["\r\n",
'--',boundary,'--\r\n'
].join(""));
}
};
两种上传方式都是用的基于表单的文件传输协议 RFC-1867 (RFC-1867 中文版)。
这两个类配合前面的拖拽代码即可实现HTML5版的拖拽上传。。。。。有了标准才是真的方便啊。。。。