建站学 - 轻松建站从此开始!

建站学-个人建站指南,网页制作,网站设计,网站制作教程

简便无刷新文件上传系统

时间:2009-12-01 22:06来源: 作者: 点击:
之前写过一个仿163网盘无刷新多文件上传系统,已经对无刷新上传文件的原理做了详细的分析。而这次的系统主要是针对单个file控件的,便携版,使用更简单,还有更深入的分析。

之前写过一个仿163网盘无刷新多文件上传系统,已经对无刷新上传文件的原理做了详细的分析。
而这次的系统主要是针对单个file控件的,便携版,使用更简单,还有更深入的分析。

兼容:ie6/7/8, firefox 3.5.5, opera 10.01, safari 4.0.3, chrome 3.0


效果预览

文件上传
选择文件 重命名 操作 状态
重置 上传超时
重置 选择文件
重置 选择文件

ps:由于需要后台,要测试系统请下载实例测试。
ps2:在完整实例文件中,还有一个文件属性查看实例。


程序说明

【upload】

程序中最重要的方法就是upload了,调用它就可以进行无刷新上传。
upload的过程是这样的,首先用stop方法停止上一次上传,并判断是否选择文件。
然后分别调用_setIframe,_setForm和_setInput,生成需要的iframe,form和input。

如果设置了timeout属性的话,会自动设置计时器:

if ( this.timeout > 0 ) {
    
this._timer = setTimeout( $$F.bind(this._timeout, this), this.timeout * 1000 );
}

ps:经测试,小于0的延时时间,ie会取消执行,而其他浏览器会当成0执行。

程序有一个_sending属性用来判断上传状态。
在stop(停止),remove(移除),_finis(完成),_timeout(超时)中会把它设为false。
而在上传开始前要把它设置为true。

最后提交表单就开始上传了。


【iframe】

程序使用_setIframe函数来创建无刷新需要的iframe。

由于ie中iframe的name不能修改的问题,要这样创建iframe:  


var iframename = "QUICKUPLOAD_" + QuickUpload._counter++,
    iframe 
= document.createElement( $$B.ie ? "<iframe name=\"" + iframename + "\">" : "iframe");
iframe.name 
= iframename;
iframe.style.display 
= "none";

ps:关于iframe的name的问题参考这里的iframe部分
ie8已经可以修改name了,但在非标准(怪辟)模式下还是不能修改。
其中使用了一个QuickUpload函数自身的_counter属性做计算器,这就能保证各个实例的iframe的name就不会重复。

为了能在文件上传完成后执行回调函数,会在iframe的onload中执行_finish函数:

Code


在ie需要用attachEvent来绑定onload,因为在ie中直接设置onload是无效的。
除了用attachEvent还可以用onreadystatechange代替。
至于原因我也不清楚,详细参考“判断 iframe 是否加载完成的完美方法”。

iframe的加载还有一个问题,测试以下代码:

Code


结果safari, chrome都会触发onload两次,而opera, ff和ie(请自行兼容)都是1次。

估计在safari和chrome在appendChild之后就进行第一次加载,并且在设置src之前加载完毕,所以触发了两次。
如果在插入body之前给iframe随便设置一个src(除了空值),间接加长第一次加载,那么也只触发一次了。
ps:不设置或空值的src相当于链接到“about:blank”(空白页)。

那么opera, ff和ie可能是第一次加载太慢,第二次覆盖了第一次的,所以只触发了一次onload。
ps:也可能是其他原因,例如浏览器优化之类的,我也不确定。

针对加载过快的问题,可以在onload的时候根据_sending确定之前是否上传状态来解决。
虽然没测试出来,会不会有_sending设置之后submit之前刚好触发第一次onload的情况呢?
针对这个问题,在upload方法中会把_sending放在submit之后设置。
那如果在submit之后_sending设置之前就触发了onload呢?(...囧)
这个情况基本不会出现,如果真的出现,就把_sending设置放到submit前面吧。

opera还有一个麻烦的问题,测试下面代码:

Code


ie和ff显示submit,onload,safari和chrome显示的是onload,submit,onload,跟上面的分析一致。
而opera却显示submit,onload,onload,两次onload都是在submit之后触发的。
这个情况就不能单纯用_sending来解决了。
是不是submit不能使iframe取消加载呢?
在appendChild之前设一个src,结果正常的只触发onload一次,看来是可以的啊。

虽然不知道原因,办法还是有的,一个是appendChild前设一个src,还可以在第一次onload中重新设置onload,像程序那样。
但这两个方法都存在不确定性,不能完全解决问题,但也找不到更好的方法了。

ff的onload还有一个问题,在出现ERROR_INTERNET_CONNECTION_RESET(文件大小超过服务器限制)之类的服务器错误时,即使加载完成也不会触发onload,暂时找不到解决办法。

iframe有一个缺陷是只能用onload判断加载完成,但没有办法判断是否加载成功。
没有类似XMLHTTP的status的东西,遇上404之类的错误也没办法判别出来。
在使用时要做好这方面的处理,例如说明允许上传文件大小,超时时间,如何处理长时间无响应等。


【form】

程序使用_setForm函数来创建用来提交数据的form。

要实现无刷新上传,要对form进行特殊的处理:

$$.extend(form, {
    target: 
this._iframe.name, method: "post", encoding: "multipart/form-data"
});

ps:详细看这里的无刷新上传部分

由于form是手动插入的,为了不影响原来页面布局还要设置一下form样式,使它“隐形”起来:

$$D.setStyle(form, {
    padding: 
0, margin: 0, border: 0,
    backgroundColor: 
"transparent", display: "inline"
});


还要注意的是,同一个表单控件只能对应一个form。
如果file控件本身已经有一个form的话,必须在提交前移除:

file.form && $$E.addEvent(file.form, "submit", $$F.bind(this.remove, this));

remove方法是用来移除程序的,包括移除form。
ps:如果提交前submit被覆盖的话要手动执行一次remove程序。

最后把form插入到dom: 

file.parentNode.insertBefore(form, file).appendChild(file);

先把form插入到file控件之前,然后把file插入到form,这样就能保证file在原来的位置上了。

(责任编辑:admin)
织梦二维码生成器
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片