zoukankan      html  css  js  c++  java
  • Facade模式实现文件上传(Flash+HTML5)

    一、前言

    确定了渐进式增强的上传方式,接下来我们需要将上传功能从具体的业务逻辑中剥离出来,作为公共组件供业务层调用。这就要求我们必须对业务层隐藏上传细节,只暴露统一的上传API。这时候大家是不是跟我一样想到了Facade模式?
     
    二、Facade模式实现文件上传,代码示例:
    /*
    上传组件,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;', 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邮箱前端团队内部分享。希望对大家有所帮助。

    五、参考资料
  • 相关阅读:
    Spring中的InitializingBean接口的使用
    解决MyBatis异常:The content of elements must consist of well-formed character data or markup.
    idea2019版与maven3.6.2版本不兼容问题
    IntelliJ IDEA更新maven依赖包
    JVM里的垃圾回收机制
    ASP.NET Core 中文文档 第四章 MVC(2.2)模型验证【转载】
    asp.net mvc Model验证总结及常用正则表达式【转载】
    SQL一次性插入大量数据【转载】
    ASP.NET Core依赖注入解读&使用Autofac替代实现【转载】
    WCF、WebAPI、WCFREST、WebService之间的区别【转载】
  • 原文地址:https://www.cnblogs.com/hellohuman/p/3946603.html
Copyright © 2011-2022 走看看