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 ...
随机推荐
- Python——requests的安装及入门-贴吧爬虫
一.windows平台下requests的安装 1.win+R,输入cmd,打开命令行窗口,输入命令:pip install requests ,即可自动安装库成功 2.输入命令:pip list,即 ...
- springcloud微服务总结三 服务客户端
一 springcloud服务理解: dubbo中服务注册和调用都是都过注解来进行的,dubbo中在service层中调用服务是通过将@service注解改变为dubbo代码架包中的service注解 ...
- 【转】org.apache.jasper.JasperException: The absolute uri: http://java.sun.com/jsp/jstl/core cannot be res
如图所示: 看网上的解决方案,有的说是jstl的版本问题,1.0版本引入使用的时候加的uri不带有jsp路径的,1.2的带有/jsp路径,还有的说是依赖冲突的问题,最后尝试了都不行,只有一招能够行的通 ...
- Idea 软件Project项目的jar依赖关系设置方法
1.查看所依赖的jar文件 (1)File--->Project Structure (2)Modules--->project01---->dependencies,可见所缺少的j ...
- Kibana6.x.x源码分析--Error: $injector:nomod Module Unavailable
首先我的依赖注入写法如下: 由于是新手,比对着Kinaba中已有的插件,进行摸索开发,但运行代码后,发现在注册依赖的时候报错了.如下截图所示: 然后根据提示:http://errors.angular ...
- hdu3966 Aragorn's Story 树链剖分
题目传送门 题目大意: 有n个兵营形成一棵树,给出q次操作,每一次操作可以使两个兵营之间的所有兵营的人数增加或者减少同一个数目,每次查询输出某一个兵营的人数. 思路: 树链剖分模板题,讲一下树链剖分过 ...
- HDU 6351 (带技巧的暴力)
题意:给定一个数,和一个最多交换次数k,问在不超过k次操作的情况,问可以得到的最大值和最小值是多少? 个人解题的艰辛路程 , 开始是想到了暴力枚举的可能 , 打出来发现在判断枚举的数组与原来数组交换了 ...
- git 项目常用命令
git remote -v 查看对应的远程仓库 git fetch origin master 将某个远程主机的更新,全部取回本地 git merge origin master 合并分支 git a ...
- Oracle Merge 使用
<转自> http://blog.csdn.net/nsj820/article/details/5755685 Oracle9i引入了MERGE命令,你能够在一个SQL语句中对一个表同时 ...
- 划分型博弈型dp
划分型动态规划: 513. Perfect Squares https://www.lintcode.com/problem/perfect-squares/description?_from=lad ...