ps:flash实现的效果是好得多,但这不是我研究的范围,也没什么可比性。
兼容: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(停止),dispose(销毁),_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函数:
复制代码 代码如下:
var finish = this._fFINISH = $$F.bind(this._finish, this);
if ( $$B.ie ) {
iframe.attachEvent( "onload", finish );
} else {
iframe.onload = $$B.opera ? function(){ this.onload = finish; } : finish;
}
在ie需要用attachEvent来绑定onload,因为在ie中直接设置onload是无效的。
除了用attachEvent还可以用onreadystatechange代替。
至于原因我也不清楚,详细参考“判断 iframe 是否加载完成的完美方法”。
iframe的加载还有一个问题,测试以下代码:
复制代码 代码如下:
<body><div>状态:</div></body>
<script>
var msg = document.getElementById("msg");
var iframe = document.createElement("iframe");
iframe.onload = function(){ msg.innerHTML += "onload,"; }
document.body.appendChild(iframe);
iframe.src = "http://cloudgamer.cnblogs.com/"
</script>
结果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还有一个麻烦的问题,测试下面代码:
复制代码 代码如下: