Facade模式实现文件上传(Flash+HTML5)
一、前言
/*
上传组件,IE浏览器默认flash上传,其它浏览器html5
示例:
var fileUpload = new FileUpload({
container: document.getElementById("uploadBtn"),
onselect: function (files) {
var self = this;
$(files).each(function (i, n) {
updateUI(n);
});
setTimeout(function () { //异步,等待onselect函数return后才能调用upload
self.upload();
}, 10);
},
onprogress: function (fileInfo) {
updateUI(fileInfo);
},
oncomplete: function (fileInfo, responseText) {
updateUI(fileInfo); }
});
*/
function FileUpload(options) {
var uploader=null;
if (options) {
//为什么要多创建一级div容器?flash 的activex创建后,再改变位置会引起activex对象失效,所以要在创建前就定好位
var div = document.createElement("div");
div.id = "flashUploadDiv";
document.body.appendChild(div);
var c = $(options.container);
//绝对定位到上传按钮的坐标,flash本身为透明遮罩
$(div).css({
position: "absolute",
left: c.offset().left + "px",
opacity:0,
top: c.offset().top + "px"
}); if ($.browser.msie || options.uploadType == "flash") { //flash上传方式
var url = "Richinfo_annex_upload.swf";
var so = new SWFObject(url, "flashupload", c.width(), c.height());
so.addParam("wmode", "transparent");
so.write("flashUploadDiv"); options.activexObj = document.getElementById("flashupload"); window.JSForFlashUpload = new FlashUpload(options);
uploader = JSForFlashUpload; } else { $(div).html(['<form style="" enctype="multipart/form-data" id="fromAttach" method="post" action="" target="frmAttachTarget">',
'<input style="height: ', c.height(), 'px;width:', c.width(), 'px" type="file" name="uploadInput" id="uploadInput" multiple="true">',
'</form>',
'<iframe id="frmAttachTarget" style="display: none" name="frmAttachTarget"></iframe>'].join(""));
options.uploadInput = document.getElementById("uploadInput");
uploader = new Html5Upload(options); }
} this.upload = function () {//触发上传请求
//alert("uploader.load");
uploader.upload();
},
this.cancel = function () {//取消上传
uploader.cancel();
}
this.getUploadFiles = function () {//获取上传队列
uploader.getUploadFiles();
} $.extend(options, this);//继承FileUpload的能力
}
var FlashUpload = function(options){
var resultObject = {
activexObj: options.activexObj,
upload:function(){
this.activexObj.uploadAll();
},
cancel: function () {
this.activexObj.cancel();
},
getUploadUrl: function () {
return this.agent.getUploadUrl();
},
getUploadFiles: function () {
return this.uploadFiles;
},
onload: function (param) {
this.agent = {};
if (options) {
this.agent = options;
}
param["filter"] = ["images图片(*.jpg;*.png;*.bmp)", "video(*.flv;*.avi;*.rmvb)"];
param["uploadFieldName"] = "filedata";
//options["filter"] = ["eml邮件(*.eml)"];
//options["filter"] = ["所有文件(*.*)"];
return param;
},
onselect: function (xmlFileList, jsonFileList) {
for (var i = 0; i < jsonFileList.length; i++) {
jsonFileList[i].fileName = decodeURIComponent(jsonFileList[i].fileName);
jsonFileList[i].state = "waiting";
/*if (jsonFileList[i].fileSize > 100000) { //大于100K不上传
jsonFileList.splice(i, 1);
i--;
}*/
}
//uploadView.onselect(jsonFileList);
this.agent.onselect && this.agent.onselect(jsonFileList);
this.uploadFiles = jsonFileList;
return jsonFileList;
},
onprogress: function (taskId, sendedSize, uploadSpeed, fileInfo) {
fileInfo.taskId = taskId;
fileInfo.sendedSize = sendedSize;
fileInfo.percent = Math.round((sendedSize / fileInfo.fileSize) * 100);
fileInfo.state = "uploading";
fileInfo.fileName = decodeURIComponent(fileInfo.fileName);//防止乱码,flash里面做了encode
//alert(fileInfo.percent);
this.agent.onprogress && this.agent.onprogress(fileInfo);
},
oncomplete: function (taskId, responseText, fileInfo) {
fileInfo.taskId = taskId;
fileInfo.state = "complete";
fileInfo.fileName = decodeURIComponent(fileInfo.fileName);//防止乱码,flash里面做了encode
this.agent.oncomplete && this.agent.oncomplete(fileInfo, responseText);
},
onerror: function (taskId, errorCode, errorMsg) {
alert("文件上传失败:" + errorMsg);
this.agent.onerror && this.agent.onerror(errorMsg);
},
onmouseover: function () {
},
onmouseout: function () {
},
onclick: function () {
return true;//返回false不会弹出文件选择框
//alert("onclick");
}
}
return resultObject;
}
var Html5Upload = function (options) {
var resultObject = {
uploadInput: null,
currentFile: null,
uploadFiles:[],//待上传的文件
completeFiles:[],//已完成的文件
init: function () {
var self = this;
this.agent = options;
this.uploadInput = options.uploadInput;
this.uploadInput.onclick = this.onclick;
this.uploadInput.onchange = function () {
var files = this.files;
var result = [];
for (var i = 0; i < files.length; i++) {
console.log(files[i]);
result.push({
fileName: files[i].name,
fileSize: files[i].size,
fileData: files[i],
state : "waiting",
taskId: Math.random().toString().substr(2)
});
}
self.uploadFiles = result;
self.onselect(result);
}
},
getFileUploadXHR: function () { //单例
if (!window.fileUploadXHR) {
fileUploadXHR = new XMLHttpRequest();
}
this.xhr = window.fileUploadXHR;
return fileUploadXHR;
},
getUploadUrl: function () { //获取上传地址
return this.agent.getUploadUrl();
},
getUploadFiles:function(){ //获取上传队列
return this.uploadFiles.concat(this.completeFiles);
},
upload: function () {//开始上传请求
this.uploadNextFile();
},
cancel:function(){ //取消上传
this.xhr.abort();
},
uploadNextFile: function () { //每个上传文件会触发
var fileInfo = this.uploadFiles.shift();
this.completeFiles.push(fileInfo); //存入已完成列表
this.currentFile = fileInfo;
if (fileInfo) {
var self = this;
var xhr = this.getFileUploadXHR();
xhr.upload.onabort = function (oEvent) { };
xhr.upload.onerror = function (oEvent) { self.onerror(oEvent); };
xhr.upload.onload = function (oEvent) { self.onload(oEvent); };
xhr.upload.onloadend = function (oEvent) { };
xhr.upload.onloadstart = function (oEvent) { };
xhr.upload.onprogress = function (oEvent) {
console.log(oEvent);
fileInfo.state = "uploading";
fileInfo.sendedSize = oEvent.position;
fileInfo.percent = Math.round((oEvent.position / oEvent.total) * 100);
self.onprogress(fileInfo);
};
//xhr.ontimeout = function(oEvent){This.ontimeout(oEvent);};
xhr.onreadystatechange = function (oEvent) {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
var responseText = xhr.responseText;
self.oncomplete(fileInfo);
}
}
};
var url = this.getUploadUrl();
xhr.open("POST", url, true);
//xhr.timeout = this.timeout; //timeout
function getFormData(fileInfo) {
var formData = new FormData();
formData.append("filedata", fileInfo.fileData);
return formData;
}
var fd = getFormData(fileInfo);
xhr.send(fd);
}
},
onclick: function () {
},
onselect:function(files){
this.agent.onselect && this.agent.onselect(files);
},
onload:function(e){
},
onprogress: function (fileInfo) {
this.agent.onprogress && this.agent.onprogress(fileInfo);
},
oncomplete: function (fileInfo) {
fileInfo.state = "complete";
this.agent.oncomplete && this.agent.oncomplete(fileInfo);
this.uploadNextFile();
}
}
resultObject.init();
return resultObject;
}
三、调用示例:
<html>
<head>
<script src="jquery-1.8.3.js"></script>
<script src="swfobject.js"></script>
<script src="upload.js"></script>
</head>
<body>
<div style="position:absolute">
</div>
<ul id="uploadList"></ul>
</body>
<script>
function updateUI(fileInfo) {
var ul = $("#uploadList");
switch (fileInfo.state) {
case "waiting":
ul.append("<li taskId='" + fileInfo.taskId + "'>" + fileInfo.fileName + "(等待上传...)</li>");
break;
case "uploading":
ul.find("li[taskId=" + fileInfo.taskId + "]").html(fileInfo.fileName + "(" + fileInfo.percent + "%)");
break;
case "complete":
ul.find("li[taskId=" + fileInfo.taskId + "]").html(fileInfo.fileName + "(完成)");
break;
}
} var fileUpload = new FileUpload({
container: document.getElementById("uploadBtn"),
//uploadType:"flash",
getUploadUrl: function () {
return "upload.ashx";
},
onselect: function (files) {
var self = this;
$(files).each(function (i, n) {
updateUI(n);
});
setTimeout(function () { //异步,等待onselect函数return后才能调用upload
self.upload();
}, 10);
},
onprogress: function (fileInfo) {
updateUI(fileInfo);
},
oncomplete: function (fileInfo, responseText) {
updateUI(fileInfo);
console.log(this.getUploadFiles());
}
});
</script>
</html>
四、结束语
以上源码仅提供上传组件化思路,实际应用中要考虑更多,比如:弱网络环境下需要分块上传,断点续传,异常情况下的日志上报等等。
以上源码非本人原创,代码来源于139邮箱前端团队内部分享。希望对大家有所帮助。
五、参考资料
Facade模式实现文件上传(Flash+HTML5)的更多相关文章
- WCF 使用Stream模式进行文件上传 --节选自Packt.Net.Framework.4.5.Expert.Programming.Cookbook
使用Stream上传文件 文件上传功能是web程序/服务上常用和必须的功能,WCF也不例外.在4.0版本之前,WCF仅仅提供了buffered模式上传文件.从4.0版本之后,WCF开始提供了Strea ...
- java实现文件上传--flash上传
1.http请求的头信息是“application/octet-stream”,request body 是二进制的flash图片流 2.把流中的信息读入到文件中 代码如下,代码分三个部分: ---- ...
- PHP fastcgi模式大文件上传500错误
最近在项目中中上传图片时,大约有300多K,结果报了个服务器错误,以前从未遇到过,错误的内容如下: mod_fcgid: www.111cn.net HTTP request length 13229 ...
- 文件上传之Html5 + jQuery上传、asp.net web api接收
HTML: <div> <label for="fileUpload"> 选择文件 </label> <br/> <input ...
- asp.net 文件上传 Uploadify HTML5 带进度条
参考的https://www.cnblogs.com/lvdabao/p/3452858.html这位,在此基础上略有修改: 1.根据Layer,将上传附件做成弹窗显示,引入frame弹窗,在项目当中 ...
- 可接受多个值的文件上传字段HTML5新特性
<input type="file" id="input" multiple="multiple"> 主要是多了个multip ...
- 强大的支持多文件上传的jQuery文件上传插件Uploadify
支持多文件上传的jQuery文件上传插件Uploadify,目前此插件有两种版本即Flash版本和HTML5版本,对于HTML5版本会比较好的支持手机浏览器,避免苹果手机Safari浏览器不支持Fla ...
- jQuery文件上传插件Uploadify(转)
一款基于flash的文件上传,有进度条和支持大文件上传,且可以多文件上传队列. 这款在flash的基础上增加了html5的支持,所以在移动端也可以使用. 由于官方提供的版本是flash免费,html5 ...
- TZ_06_SpringMVC_传统文件上传和SpringMVC文件上传方式
1.传统文件上传方式 <!-- 文件上传需要的jar --> <dependency> <groupId>commons-fileupload</groupI ...
随机推荐
- php常用的系统函数大全
字符串函数 strlen:获取字符串长度,字节长度 substr_count 某字符串出现的次数 substr:字符串截取,获取字符串(按照字节进行截取) mb_strlenmb_substr str ...
- 3-19bug随即
#方案录入 ### 国外网络访问,录入添加图片,上传后图片显示不出. ``` * 后台有返回数据,前端显示巨慢,待检查 * ``` ### 产品信息,富文本信息加载不出
- 1、TensorFlow简介
参考:http://www.tensorfly.cn/tfdoc/get_started/basic_usage.html 1.用TensorFlow构造一个简单的线性拟合: # -*- coding ...
- mvc 请求处理管道
原文 http://blog.csdn.net/wulex/article/details/41514795 当一个asp.net mvc应用程序提出请求,为了响应请求,包含一些请求执行流程步骤! 在 ...
- 精通 WPF UI Virtualization (提升 OEA 框架中 TreeGrid 控件的性能)
原文:精通 WPF UI Virtualization (提升 OEA 框架中 TreeGrid 控件的性能) 本篇博客主要说明如何使用 UI Virtualization(以下简称为 UIV) 来提 ...
- A. Right-Left Cipher Round #528 (Div. 2)【字符串】
一.题面 题目链接 二.分析 该题就是一个字符串的还原.长度为奇数时从左边开始,长度为偶数时从右边开始. 三.AC代码 #include <bits/stdc++.h> using nam ...
- POJ_3126 Prime Path 【BFS+素数打表】
一.题目 http://poj.org/problem?id=3126 二.分析 该题主要是要让我们找到一个$4$位素数到另一个$4$位素数的最少的变换次数,且要求保证每一次变换都满足 1.下一个数必 ...
- Karma+Jasmine测试环境搭建
1.如果你还没安装node的话,去这里下载:http://nodejs.cn/download/,选择跟你电脑匹配的并进行安装,一路next下来就行,路径最好改成自己让自己舒服的,默认的路径可能会很让 ...
- lambda 表达式定制操作
泛型算法中的定制操作 许多算法都会比较输入序列中的元素以达到排序的效果,通过定制比较操作,可以控制算法按照编程者的意图工作. 普通排序算法: template<class RandomItera ...
- 【VBA研究】Excel VBA利用ADODB访问数据库使用小结
[转自] http://blog.csdn.net/iamlaosong/article/details/18043433 作者:iamlaosong ▲连接Oracle数据库 Set cnn = C ...