一个简单的异步上传组件
工作需要,要写一个简单的文件异步上传功能,首先想到的是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>