一个简单的异步上传组件

工作需要,要写一个简单的文件异步上传功能,首先想到的是jquery的ajaxUpload组件,但是公司用的是tangram,为了这样的一个功能再去引一个jquery实在太亏了;问了一圈同事好像都没有提供这个功能的“库存”,只好自己写了。

查了一些资料,实现单文件异步提交还是很简单的。大致思路是 生成一个form表单,target到iframe中去,由后端进行处理,然后再把上传结果信息以html 里的JS全局变量形式返回到iframe,外层实时监听iframe里的JS全局变量即可 。(看起来像是发起跨域异步请求的方法,但事实上这是不支持跨域的)

还有一点需要注意的是, 如果需要修改提交表单的样式,最佳方案是隐藏当前表单 (这里是指:opacity: 0;或 filter:progid:DXImageTransform.Microsoft.Alpha(opacity:0);),然后在下面加上按钮背景。

JS代码如下:

(function($, ns){
    "use strict";

    function ajaxUpload(cfg){
        this.name = cfg.name || "";
        this.rendId = cfg.rendId;
        this.actionUrl = cfg.actionUrl || '/sec/forgot/appeal/upload';
        this.method = cfg.method || "post";
        this.data = cfg.data;
        this.status = '0';//初始状态

        this.onSuccess = cfg.onSuccess || function(){};
        this.onSending = cfg.onSending || function(){};
        this.onFailure = cfg.onFailure || function(){};

        var _init = function(me){
            me.init();
        }
        _init(this);
    }

    ajaxUpload.prototype.init = function(){

        this.render();
    }

    ajaxUpload.prototype.hiddenTpl = function(){
        var hiddenTpl = '';
        for(var item in this.data){
            hiddenTpl = hiddenTpl + '<input type="hidden" name="'+item+'" value="'+this.data[item]+'">'
        }
        return hiddenTpl;
    }

    ajaxUpload.prototype.getTpl = function(){
        return {
            wrapper:'<div class="ajaxUpload">',
            buttonEle:'<div class="ajaxUpload-show clearfix" ><button class="ajaxUpload-button">选择文件</button><span class="ajaxUpload-info"></span></div>',
            form:''+
        '<form class="ajaxupload-form" enctype="multipart/form-data" target="ajaxUploadIframe" action="'+this.actionUrl+'" method="'+this.method+'">'+
            '<input type="file" name="'+this.name+'" class="ajaxupload-form-file"/>'+
            '<input type="hidden" name="picid" class="ajaxupload-form-picid" value="">'+
            this.hiddenTpl()+
        '</form>',
            iframe:''+
        '<iframe class="ajaxupload-iframe" name="ajaxUploadIframe" style="display:none"></iframe>'
        }
    }

    ajaxUpload.prototype.render = function(){
        var tpl = this.getTpl(),
            ele = {},
            me = this;

        ele.wrapper = $(tpl.wrapper);
        ele.formEle = $(tpl.form);
        ele.buttonEle = $(tpl.buttonEle);
        ele.iframeEle = $(tpl.iframe);

        $('#'+this.rendId).append(ele.wrapper);
        $(ele.wrapper).append(ele.buttonEle);
        $(ele.wrapper).append(ele.formEle);
        $(document.body).append(ele.iframeEle);

        ele.fileEle = $('.ajaxUpload .ajaxupload-form-file');
        ele.picidEle = $('.ajaxUpload .ajaxupload-form-picid');
        ele.msgEle = $('.ajaxUpload .ajaxUpload-info');

        this.ele = ele;

        $(ele.buttonEle).on('click',function(){
            ele.fileEle.trigger('click');
        })
        $(ele.fileEle).on('change',function(event){
            var filesData = {};
            if(event.target.files && event.target.files[0]){
                filesData.type = event.target.files[0].type;
                filesData.name = event.target.files[0].name;
                filesData.size = event.target.files[0].size;
            }else if(event.target && event.target.value){
                filesData.type = 'image/' + event.target.value.substr(event.target.value.lastIndexOf('.')+1);
                filesData.name = event.target.value.substr(event.target.value.lastIndexOf('\\')+1);
                filesData.size;
            }
            me.changeFile(filesData,me.renderResult)
        })
    };
    ajaxUpload.prototype.renderResult =function(result,me){

        if(result.errno == '110000'){
            me.status = '6';//上传成功
            me.ele.picidEle.val(result.picid);
            me.onSuccess(result,me);
            me.changeMsgView('done');
        }else{
            me.onFailure(result,me);
            me.changeMsgView('fail');

            me.status = '5';//上传失败
            me.ele.msgEle.html(result.msg)
        }
    };
    ajaxUpload.prototype.changeMsgView = function(type){
        if(type == 'sending'){
            this.ele.msgEle.addClass('sending');
            this.ele.msgEle.removeClass('done');
            this.ele.msgEle.removeClass('fail');
        }else if(type == 'done'){
            this.ele.msgEle.addClass('done');
            this.ele.msgEle.removeClass('sending');
            this.ele.msgEle.removeClass('fail');
        }else if(type == 'fail'){
            this.ele.msgEle.addClass('fail');
            this.ele.msgEle.removeClass('sending');
            this.ele.msgEle.removeClass('done');
        }
    }
    ajaxUpload.prototype.changeFile =function(files,callback){
        var type = files.type.toLowerCase(),
            size = files.size || '',
            name = files.name || '',
            allowType = 'image/png'+','+'image/jpg'+','+'image/bmp'+','+'image/jpeg'+','+'image/gif',
            err = {
                errno:'',
                msg:''
            },
            interval,
            result = '',
            me = this;

            this.status = '1';
            me.changeMsgView('sending');
            me.ele.msgEle.html(name);

        if(allowType.indexOf(type) == -1){
            err.msg = '文件格式错误'
            return callback(err,me);
        }else if(size && size>1024000){
            err.msg = '您上传的图片过大,请上传小于1M的图片吧'
            return callback(err,me);
        }else{
            $(this.ele.formEle).submit();
            var times = 0;
            this.onSending && this.onSending(me);

            interval = setInterval(function(){

                if(times<90){
                    result = window.frames ? window.frames['ajaxUploadIframe'].ajaxUpload : me.ele.iframeEle[0].contentDocument ? me.ele.iframeEle[0].contentDocument.ajaxUpload: me.ele.iframeEle[0].contentWindow ? me.ele.iframeEle[0].contentWindow.ajaxUpload:'';
                    if(result){
                        clearInterval(interval);
                        err.msg = result.msg;
                        err.errno = result.errno;
                        err.picid = result.picid;
                        err.name = name;
                        me.status = '4';//上传有结果
                        return callback(err,me);
                    }
                    times++
                    me.status = '3';//上传中
                }else{
                    me.ele.msgEle.removeClass('sending');
                    me.ele.msgEle.removeClass('done');

                    me.status = '2';//上传超时
                    clearInterval(interval)
                    err.msg = '上传超时,请稍后再试!';
                    return callback(err,me);
                }
            },1000)
        }
    };

    ns.define('module/ajaxUpload', ajaxUpload);
})(baidu, window.Pass);

返回上传信息的HTML代码如下:

<!doctype html>
<html>
<head>
    <meta charset='utf-8'/>
    <script type="text/javascript" charset="UTF-8" >
    var ajaxUpload = {
        "errno":'',
        "msg":'',
        "picid":''
    }
    </script>
</head>
    <body>
    </body>
</html>