在项目中使用了Juploader 1.0无刷新上传文件的js组件,在IE8以上没有问题,代码如下:
function InitialUploadDirectly(OnUploadFunc, buttonID, allowedExts) { $.jUploader({ button: buttonID, // 这里设置按钮id eventType: 1, //触发类型 addeventbutton: buttonID, // 要绑定事件的元素的id filenamed: buttonID + 'divFileName', //存放选择的文件路径的文本框的id checkMethod: function () { return checkForm(); }, afterChoose: function (fileName) { afterUpload(fileName, buttonID); }, allowedExtensions: allowedExts, // 设置允许上传的后缀,当然最好在服务器端也做验证 // 开始上传事件 onUpload: function (fileName) { var url = "**.ashx"; if (OnUploadFunc != null) { url = OnUploadFunc(); } $.jBox.tip("正在上传文件,请稍候!", "loading"); return url; }, // 上传完成事件 onComplete: function (fileName, response) { // response是json对象,格式可以按自己的意愿来定义,例子为: { success: true, fileUrl:'' } console.log(response); if (response.Msg == "success") { AfterUploadCompleteSuccess(response.AddedFile.S_ID, fileName); } else if (response.Msg == "error") { jBox.closeTip(); jBox.error("文件大小不能超过50M", "错误提示"); } else { jBox.closeTip(); jBox.error(response.Msg, "错误提示"); } }, // 系统信息显示(例如后缀名不合法) showMessage: function (message) { jBox.tip(message, 'error'); }, // 取消上传事件 onCancel: function (fileName) { jBox.tip(fileName + ' 上传取消。', 'info'); }, // 自己定义文字 messages: { upload: '添加附件...', emptyFile: "{file} 为空,请选择一个文件.", invalidExtension: "{file} 后缀名不合法. 只有 {extensions} 是允许的.", onLeave: "文件正在上传,如果你现在离开,上传将会被取消。" } }); }
但是使用Chrome(我测试的版本为31)浏览器测试的时候,虽然服务器已经接收到上传的文件,并且返回了json格式的数据对象,但是前台脚本中始终得不到返回值,response始终为{“Msg”:”error”},查看Jquploader的源码,发现response是在complete事件中try catch 中异常情况中赋的值,下面代码中黄色标识的部分
var complete = function () { try { options.uploading = false; $('#jUploader-file' + options.id).show(); options.button.children('span').text(options.messages.upload); var iframe = $('#jUploaderIframe' + options.id).get(0); // when we remove iframe from dom // the request stops, but in IE load // event fires if (!iframe.parentNode) { return; } // fixing Opera 10.53 if ((iframe.contentDocument && iframe.contentDocument.body && iframe.contentDocument.body.innerHTML == "false") || (iframe.contentWindow.document && iframe.contentWindow.document.body && iframe.contentWindow.document.body.innerHTML == "false")) { // In Opera event is fired second time // when body.innerHTML changed from false // to server response approx. after 1 sec // when we upload file with iframe return; } // iframe.contentWindow.document - for IE<7 var doc = iframe.contentDocument ? iframe.contentDocument : iframe.contentWindow.document; var response; log("innerHTML = " + doc.body.innerHTML); try { var json = doc.body.innerHTML.replace(/<pre>(.*)<\/pre>/g, '$1'); response = eval("(" + json + ")"); } catch (e) { response = { "Msg": "error" }; //throw e; } console.log(response); // timeout added to fix busy state in FF3.6 setTimeout(function () { $('#jUploaderForm' + options.id).remove(); $('#jUploaderIframe' + options.id).remove(); }, 10); options.onComplete(options.fileName, response); } catch (e) { setTimeout(function () { $('#jUploaderForm' + options.id).remove(); $('#jUploaderIframe' + options.id).remove(); }, 10); response = { "Msg": "error" }; options.onComplete(options.fileName, response); } };
继续调试发现下面这段代码中
var json = doc.body.innerHTML.replace(/<pre>(.*)<\/pre>/g, '$1');的json始终为空,但是实际上后台是返回了值的。
继续查看源码,明白了Juploader的基本思想,是在页面中创建iframe,再在iframe中构建一个form,form的action指向上传文件的后台服务器地址,如下:
$(document.body).append(createIframe()).append(createForm());
并且在iframe的onload事件中绑定自定义的complete方法,如下:
var createIframe = function () { var id = 'jUploaderIframe' + options.id; var iframe = $('<iframe id="' + id + '" name="' + id + '" src="javascript:false;" style="display:none"></iframe>').bind('load', complete); return iframe; };
这样在iframe中的form加载完成后会执行iframe的onload事件(具体iframe的onload事件的用法,可自行百度,这里不多做解释了)。
但是在调试过程中却发现onload的事件总是先执行,也就是说complete方法在执行的时候form其实还没有加载完成,以下是控制台日志显示内容:
于是怀疑是因为代码顺序的问题造成的,再看一下具体的代码
createIframe方法中:
var iframe = $('<iframe id="' + id + '" name="' + id + '" src="javascript:false;" style="display:none"></iframe>').bind('load', complete);
upload方法中:
$(document.body).append(createIframe()).append(createForm());
于是调整代码在iframe append form 后,再bind iframe 的onload事件
createIframe方法中
var iframe = $('<iframe id="' + id + '" name="' + id + '" src="javascript:false;" style="display:none"></iframe>')
去掉了bind load 的事件
而在upload方法中:
var ifrm = createIframe(); $(document.body).append(ifrm).append(createForm()); ifrm.bind("load", complete);
这样修改之后,上传完成事件onComplete 的response参数就可以正常获取form 中action 页面的回传值了