仿163网盘无刷新文件上传系统
【文件列表】
在上面的Ini函数中,最后执行了一个附加函数onIni,这个函数是用户自己定义的,我就在这个函数中添加文件列表。
在之前先说说添加文件列表的函数AddList,这个函数是用来把file控件的值列在一个table里面。
函数的参数是一个二维数组,其中第一维是行(tr),第二维是列(td)。
首先获取列表对象FileList,再定义一个文档碎片oFragment来操作dom:
然后用两个Each把二维数组插入到文档碎片中:
Each(rows, function(cells){
var row = document.createElement("tr");
Each(cells, function(o){
var cell = document.createElement("td");
if(typeof o == "string"){ cell.innerHTML = o; }else{ cell.appendChild(o); }
row.appendChild(cell);
});
oFragment.appendChild(row);
})
其中用了一个判断if(typeof o == "string"),如果是文本就直接用innerHTML插入td,如果不是文本(这里不是文本就是一个对象)就用appendChild插入到td。
当数据都插入到文档碎片,就准备把文档碎片插入到FileList中,不过还有一个步骤就是清空FileList中原有的数据。
本来把innerHTML设为空来清空FileList会更有效率,但ie的table中只有td支持innerHTML,所以只好用removeChild来清空:
之后就可以把文档碎片插入了:
继续看onIni函数,现在只需要把要显示的数据组成一个二维数组,再用AddList就能显示文件列表了,这时存放file控件集合的Files属性就大有用处了。
首先定义一个放显示数据的数组:
然后根据Files对这个数组赋值:
if(this.Files.length){
var oThis = this;
Each(this.Files, function(o){
var a = document.createElement("a"); a.innerHTML = "取消"; a.href = "javascript:void(0);";
a.onclick = function(){ oThis.Delete(o); return false; };
arrRows.push([o.value, a]);
});
} else { arrRows.push(["没有添加文件", " "]); }
AddRow(arrRows);
当Files没有控件时只是输出“没有添加文件”,有控件时就会把每个file控件的要显示数据放到一个数组中,可以看到这个数组其实就是td内容的集合,接着把这个数组加入到arrRows中形成二维数组,最后把得到的arrRows给AddRow函数显示数据就行了。
为了能取消指定的file控件,这里插入了一个a来触发删除函数Delete,这里也有一个技巧,这里把href设为"javascript:void(0);",并在onclick中返回false,这样能最大程度的实现仅仅执行js而不去跳转。
在表单提交时也要重新显示文件列表,表单提交后就不允许删除文件了,只显示文件路径就行了:
$("idBtnupload").onclick = function(){
//显示文件列表
var arrRows = [];
Each(fu.Files, function(o){ arrRows.push([o.value, " "]); });
AddList(arrRows);
fu.Folder.style.display = "none";
$("idProcess").style.display = "";
$("idMsg").innerHTML = "正在添加文件到您的网盘中,请稍候……有可能因为网络问题,出现程序长时间无响应,请点击“取消”重新上传文件";
fu.Form.submit();
}
说到表单提交要注意一个问题,就是表单是不能嵌套的,最好是把表单放到服务器表单之外,没有办法才使用服务器表单作为提交表单(由于程序会修改提交表单的属性,所以尽量不要这样使用)。
这样文件列表就完成了,有兴趣的话也可以自己封装一下这个功能。
【file样式】
到此,程序的功能都已经实现了,但在163网盘中还有一个特别的地方,就是file控件的样式。
如果有用过163网盘上传文件,就知道那个file控件就像一个按钮,但功能确实是一个file控件。
但当自己尝试修改file控件的样式时,发现单单设置file控件的样式并不能实现想要的效果。
于是我想了另一个办法,用一个button来模拟,结果发现也不行,用js根本操作不了file控件,应该是考虑到安全问题吧。
最后是参考了163网盘和muxrwc模拟126附件添加的效果,总结了这个方法:
1.指定用一个容器(例如程序中的idFile)。
容器最好指定高和宽,并且overflow为hidden,不是块级元素的最好设display为block(为了高和宽的正确呈现);
2.在容器里放一个file控件,并设置样式,使能触发弹出选择文件框的部分覆盖整个容器,并设置成全透明。
容器指定准确的高和宽就是为了能通过file控件中不多的能设置的样式来覆盖整个容器;
3.现在已经把容器模拟成file控件了,可以直接设置容器的样式来模拟设置file控件的样式了。
在程序中主要用file控件的margin-left和font-size来实现覆盖整个容器:
a.files input {
margin-left:-350px;
font-size:30px;
cursor:pointer;
filter:alpha(opacity=0);
opacity:0;
}
至于容器,我使用了有伪类hover的a元素(虽然CSS2中hover可以应用于任何对象,但ie6不支持)。
这里用了一个常用的小技巧,就是用一张图片作为背景通过在hover时修改background-position来实现两张图片的效果:
a.files {
width:90px;
height:30px;
overflow:hidden;
display:block;
border:1px solid #BEBEBE;
background:url(img/fu_btn.gif) left top no-repeat;
text-decoration:none;
}
a.files:hover {
background-color:#FFFFEE;
background-position:0 -30px;
}
在点击这个a时后会出现一个虚线框,在这里显然不太美观,可以把outline设为none来去掉,可是ie又不支持,在网上找到一个方法ie可以把hideFocus设为true来隐藏聚焦(即不显示这个虚线框,hideFocus可以在js或html中设置,也可以通过expression放到css中:
a.files, a.files input {
outline:none;/*ff* /
hide-focus:expression(this.hideFocus=true);/*ie* /
}
这样完全模拟了163网盘的效果了。