这个仿163网盘无刷新文件上传系统,并没有用使用.net的控件,完全的手工制作。前台基本上是静态的,跟后台没有关系,所以后台用什么语言做都可以(后面有各个版本的实例下载)。 本来觉得这个系统会很复杂,但把每个部分都分析清楚后,其实需要的技术并不高。不过当我把各个功能函数都整理好准备进行封装时,却发现要把程序封装不是那么容易,因为程序跟html的耦合度太高。然后我逐步把程序中操作html相关的部分分离出来,首先把简单的分离,接着是文件列表,然后是file控件,最后是一些提示性程序。经过几次尝试才把整个结构封装好,现在程序结构应该算比较清晰,有什么不明白的地方欢迎留言。 效果预览 .fu_list {width:600px;background:#ebebeb;font-size:12px;}.fu_list td {padding:5px;line-height:20px;background-color:#fff;}.fu_list table {width:100%;border:1px solid #ebebeb;}.fu_list thead td {background-color:#f4f4f4;}.fu_list b {font-size:14px;}/*file容器样式*/a.files {width:90px;height:30px;overflow:hidden;display:block;border:1px solid #BEBEBE;background:url(http://images.cnblogs.com/cnblogs_com/cloudgamer/fu_btn.gif) left top no-repeat;text-decoration:none;}a.files:hover {background-color:#FFFFEE;background-position:0 -30px;}/*file设为透明,并覆盖整个触发面*/a.files input {margin-left:-350px;font-size:30px;cursor:pointer;filter:alpha(opacity=0);opacity:0;}/*取消点击时的虚线框*/a.files, a.files input {outline:none;/*ff*/hide-focus:expression(this.hideFocus=true);/*ie*/} 上传文件 添加文件: 文件路径
温馨提示:最多可同时上传 个文件,只允许上传 文件。 这里的预览只是前台的效果,要整个系统测试请下载完整实例。 程序说明【无刷新上传】 要实现文件上传,form必须设置几个属性: 1.action:设为要处理数据的页面地址; 2.method:设为"post"; 3.enctype/encoding:必须设为"multipart/form-data",这里要注意的是在ie中用js修改form的enctype属性是没有效果的,只能修改encoding;
后面两个属性程序初始化时都有设置:
this .Form.method = " post " ; this .Form.encoding = " multipart/form-data " ;
要注意这里的无刷新不是ajax哦,而是利用“古老”的iframe。 由于ajax提交数据必须先获取数据,而js(一般情况下)是不能操作客户端文件,要获取文件数据就更不用说了,所以只能用iframe来做。 先说说iframe实现无刷新上传的原理:利用form的target属性,把数据提交到页面中一个(通常为隐藏的)iframe上。 直观点说就是把“刷新”留给iframe。 其实原理跟一般用iframe实现无刷新提交表单是一样的,只是这里换成是文件。 这里关键就是把form的target设为iframe的name:
this .Form.target = this ._FrameName;
【iframe】 如果没有自定义iframe,程序在初始化时会自动创建无刷新所需的iframe的。 首先必须选择一个iframe名,这在无刷新时是必须的,为了每个实例能创建各自的iframe,这里用了一个随机数:
this ._FrameName = " uploadFrame_ " + Math.floor(Math.random() * 1000 );
也可以用一个递增的计算器来代替随机数。
接着创建iframe,本以为用document.createElement("iframe")创建再设置它的name属性就行了。 却发现这样设置的name在ie居然不认(有说name是只读属性),还好在网上找到一个方法:“IE 创建元素,还有一个特点,就是可以连同属性一同创建”。 例如我想给动态创建的iframe设置name,可以这样:
document.createElement( " <iframe name=/ "" + this._FrameName + " / " > " )
不过这个方式在ff会报错: uncaught exception: String contains an invalid character (NS_ERROR_DOM_INVALID_CHARACTER_ERR) 估计是用createElement时不能带name,标准应该也是这样,所以兼容的方式这样写:
Code var oFrame = isIE ? document.createElement( " <iframe name=/ "" + this._FrameName + " / " > " ) : document.createElement( " iframe " ); // 为ff设置name oFrame.name = this ._FrameName; oFrame.style.display = " none " ; 关于这方面更详细的内容请看这里。 创建完还需要插入到body中,一般的做法是使用document.body.appendChild,但在ie中会有“已终止操作”错误,可以用下面这段代码测试:
Code < body > < div > < script > document.body.appendChild(document.createElement(" div " )); < / script> < / div> < / body> 网上找到一个解析:“原来FF下的实现机制是当页面还没有完全读取完时body元素就已经存在了,而IE只有页面完全读取结束body元素才会存在,所以在页面中插入上面这条语句在IE下就会出现错误”。 我在web开发未解之谜中也提到了这个现象,我这里使用了insertBefore代替:
document.body.insertBefore(oFrame, document.body.childNodes[ 0 ]);
在服务器端文件传送完(或失败)之后,怎么通知客户端呢? 这里说说我的方法,首先我在客户端定义一个函数:
function Finish(msg){ alert(msg); location.href = location.href; }
很简单,就是显示提示并重新加载页面(如果使用reload会导致ff中iframe重复加载数据)。 那服务器端如何通知客户端的问题,就是iframe如何跟主页面交互。 答案是通过window.parent或window.top,在iframe中parent和top属性“分别返回立即父窗口和最上层的祖先窗口”。 例如我在服务器端处理完数据之后会输出:
context.Response.Write( " <script>window.parent.Finish(' " + _msg + " ');</script> " );
就会执行主页面的Finish函数了。
【多文件上传】 对于多文件上传,这里的目的是如何做到163网盘那样,只用一个file控件就实现多文件上传。 这里参考了163网盘的思路,下面说说如何实现: 首先必须有一个文件空间(我自己定的名字),例如程序中的"idFile"对象,这个空间不需要内容甚至一个div就可以,主要是用来存放file控件,程序中Folder属性就是这个文件空间对象。 ps:这里的要求是把file控件都控制在文件空间里,即使不是单file控件的情况。 再说说Files属性,这个属性放的是file控件集合,方便获取file控件,在下面“文件列表”就会用到。
处理这些file控件的程序主要在Ini函数中: 首先是处理文件空间中的file控件:
Code this .Files = []; // 整理文件空间,把有值的file放入文件集合 Each( this .Folder.getElementsByTagName( " input " ), Bind( this , function (o){ if (o.type == " file " ){ o.value && this .Files.push(o); this .onIniFile(o); } })) 可以看到这里主要是把file控件放入到Files中,并执行附加函数onIniFile,我是这样定义这个函数的:
onIniFile: function (file){ file.value ? file.style.display = " none " : this .Folder.removeChild(file); }
这里为了实现单file控件,把原来有值的file都隐藏了,还有那个“单file控件”呢? 别急,接着就在文件空间插入一个新的file控件:
Code var file = document.createElement( " input " ); file.name = this .FileName; file.type = " file " ; file.onchange = Bind( this , function (){ this .Check(file); this .Ini(); }); this .Folder.appendChild(file); 可以看到file控件的name是FileName属性的值,默认是空的,如果服务器端需要这个name的话就可以设置。 这里可以看到每个file控件都有onchange来执行检测函数Check,这样每次选择文件后都会用Check检测一次,这里说说这个Check函数:
Code // 检测变量 var bCheck = true ; // 进行空值、文件数、后缀名、同值检测 if ( ! file.value){ bCheck = false ; this .onEmpty(); } else if ( this .Limit && this .Files.length >= this .Limit){ bCheck = false ; this .onLimite(); } else if ( !! this .ExtIn.length && ! RegExp( " /.( " + this .ExtIn.join( " | " ) + " )$ " , " i " ).test(file.value)){ // 检测是否允许后缀名 bCheck = false ; this .onNotExtIn(); } else if ( !! this .ExtOut.length && RegExp( " /.( " + this .ExtOut.join( " | " ) + " )$ " , " i " ).test(file.value)) { // 检测是否禁止后缀名 bCheck = false ; this .onExtOut(); } else if ( !! this .Distinct) { Each( this .Files, function (o){ if (o.value == file.value){ bCheck = false ; } }) if ( ! bCheck){ this .onSame(); } } 里面有一个检测变量bCheck,然后进行空值、文件数限制、后缀名、相同文件的检测,当其中一个步骤不通过bCheck就会设为false,一个常用的检测结构。 这里说说检测后缀名,由于js不能像后台那样获取文件的文件类型,所以只能根据后缀名来判断,例如用正则判断:
/ /.(jpg|gif)$ / i.test(file.value)
这样判断显然是不够的,所以如果要做文件类型判断的话一定要在后台用ContentType再判断一次。 最后如果没有通过检测就会执行onFail函数:
! bCheck && this .onFail(file);
我在onFail函数中设定了移除没有通过检测的file控件:
onFail: function (file){ this .Folder.removeChild(file); }
这样就基本实现(正确的说是模拟)了单file控件上传多个文件的效果了。
【文件列表】 在上面的Ini函数中,最后执行了一个附加函数onIni,这个函数是用户自己定义的,我就在这个函数中添加文件列表。
在之前先说说添加文件列表的函数AddList,这个函数是用来把file控件的值列在一个table里面。 函数的参数是一个二维数组,其中第一维是行(tr),第二维是列(td)。 首先获取列表对象FileList,再定义一个文档碎片oFragment来操作dom:
var FileList = $( " idFileList " ), oFragment = document.createDocumentFragment();
然后用两个Each把二维数组插入到文档碎片中:
Code 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来清空:
while (FileList.hasChildNodes()){ FileList.removeChild(FileList.firstChild); }
之后就可以把文档碎片插入了:
FileList.appendChild(oFragment);
继续看onIni函数,现在只需要把要显示的数据组成一个二维数组,再用AddList就能显示文件列表了,这时存放file控件集合的Files属性就大有用处了。 首先定义一个放显示数据的数组:
var arrRows = [];
然后根据Files对这个数组赋值:
Code 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([ " <font color='gray'>没有添加文件</font> " , " " ]); } AddRow(arrRows); 当Files没有控件时只是输出“没有添加文件”,有控件时就会把每个file控件的要显示数据放到一个数组中,可以看到这个数组其实就是td内容的集合,接着把这个数组加入到arrRows中形成二维数组,最后把得到的arrRows给AddRow函数显示数据就行了。 为了能取消指定的file控件,这里插入了一个a来触发删除函数Delete,这里也有一个技巧,这里把href设为"javascript:void(0);",并在onclick中返回false,这样能最大程度的实现仅仅执行js而不去跳转。
在表单提交时也要重新显示文件列表,表单提交后就不允许删除文件了,只显示文件路径就行了:
Code $( " 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 = " 正在添加文件到您的网盘中,请稍候……<br />有可能因为网络问题,出现程序长时间无响应,请点击“<a href='?'><font color='red'>取消</font></a>”重新上传文件 " ; 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来实现覆盖整个容器:
Code 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来实现两张图片的效果:
Code 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中:
Code a.files, a.files input { outline: none ; /* ff* / hide-focus:expression(this.hideFocus=true);/*ie* / } 这样完全模拟了163网盘的效果了。
【后台】
前台基本完成了,就到后台啦。后台的功能很简单,就是处理传递过来的文件数据。 这里像js + .Net 图片切割系统那样使用ashx文件处理IHttpHandler发送过来的数据。 程序很简单,就直接贴代码了:
Code int iTotal = context.Request.Files.Count; if (iTotal == 0 ) { _msg = " 没有数据 " ; } else { int iCount = 0 ; for ( int i = 0 ; i < iTotal; i ++ ) { HttpPostedFile file = context.Request.Files[i]; if (file.ContentLength > 0 || ! string .IsNullOrEmpty(file.FileName)) { // 保存文件 file.SaveAs(System.Web.HttpContext.Current.Server.MapPath( " ./file/ " + Path.GetFileName(file.FileName))); // 这里可以根据实际设置其他限制 if ( ++ iCount > UploadFileLimit) { _msg = " 超过上传限制: " + UploadFileLimit; break ; } } } } 这里只检测了有无文件和文件数限制,其他检测如文件大小等可以自己扩展,应该不难。 处理完数据之后就通知客户端:
context.Response.Write( " <script>window.parent.Finish(' " + _msg + " ');</script> " );
这个在上面iframe的内容中已经说明了。
使用说明
基本使用很简单,实例化一个file对象,其中参数分别是form对象,文件空间对象:
new FileUpload( " uploadForm " , " idFile " )
这样就实现了一个简单的无刷新上传文件表单。
还可以使用这几个属性: Form//表单 Folder//文件控件存放空间 Files//文件集合
更多的功能可以选择设置这些属性: 属性名:默认值//说明 FileName:"",//文件上传控件的name,配合后台使用 FrameName:"",//iframe的name,要自定义iframe的话这里设置name onIniFile:function(){},//整理文件时执行(其中参数是file对象) onEmpty:function(){},//文件空值时执行 Limit:0,//文件数限制,0为不限制 onLimite:function(){},//超过文件数限制时执行 Distinct:true,//是否不允许相同文件 onSame:function(){},//有相同文件时执行 ExtIn:[],//允许后缀名 onNotExtIn:function(){},//不是允许后缀名时执行 ExtOut:[],//禁止后缀名,当设置了ExtIn则ExtOut无效 onExtOut:function(){},//是禁止后缀名时执行 onFail:function(){},//文件不通过检测时执行(其中参数是file对象) onIni:function(){}//重置时执行
使用方法可以参考实例。
程序中提供了下面几个方法: Ini 整理空间 Check 检测file对象 Delete 删除指定file Clear 删除全部file
完整程序 样式设置
Code .fu_list { width: 600px ; background: #ebebeb ; font-size: 12px ; } .fu_list td { padding: 5px ; line-height: 20px ; background-color: #fff ; } .fu_list table { width: 100% ; border: 1px solid #ebebeb ; } .fu_list thead td { background-color: #f4f4f4 ; } .fu_list b { font-size: 14px ; } /* file容器样式 */ 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 ; } /* file设为透明,并覆盖整个触发面 */ a.files input { margin-left: -350px ; font-size: 30px ; cursor: pointer ; filter: alpha(opacity=0) ; opacity: 0 ; } /* 取消点击时的虚线框 */ a.files, a.files input { outline: none ; /* ff */ hide-focus: expression(this.hideFocus=true) ; /* ie */ } html代码
Code < form id ="uploadForm" action ="File.ashx" > < table border ="0" cellspacing ="1" class ="fu_list" > < thead > < tr > < td colspan ="2" >< b > 上传文件 </ b ></ td > </ tr > </ thead > < tbody > < tr > < td align ="right" width ="15%" style ="line-height:35px;" > 添加文件: </ td > < td >< a href ="javascript:void(0);" class ="files" id ="idFile" ></ a > < img id ="idProcess" style ="display:none;" src ="img/loading.gif" /></ td > </ tr > < tr > < td colspan ="2" >< table border ="0" cellspacing ="0" > < thead > < tr > < td > 文件路径 </ td > < td width ="100" ></ td > </ tr > </ thead > < tbody id ="idFileList" > </ tbody > </ table ></ td > </ tr > < tr > < td colspan ="2" style ="color:gray" > 温馨提示:最多可同时上传 < b id ="idLimit" ></ b > 个文件,只允许上传 < b id ="idExt" ></ b > 文件。 </ td > </ tr > < tr > < td colspan ="2" align ="center" id ="idMsg" >< input type ="button" value ="开始上传" id ="idBtnupload" disabled ="disabled" /> < input type ="button" value ="全部取消" id ="idBtndel" disabled ="disabled" /> </ td > </ tr > </ tbody > </ table > </ form > 程序代码
Code var isIE = (document.all) ? true : false ; var $ = function (id) { return " string " == typeof id ? document.getElementById(id) : id; }; var Class = { create: function () { return function () { this .initialize.apply( this , arguments); } } } var Extend = function (destination, source) { for ( var property in source) { destination[property] = source[property]; } } var Bind = function (object, fun) { return function () { return fun.apply(object, arguments); } } var Each = function (list, fun){ for ( var i = 0 , len = list.length; i < len; i ++ ) { fun(list[i], i); } }; // var FileUpload = Class.create(); FileUpload.prototype = { // 表单对象,文件控件存放空间 initialize: function (form, folder, options) { this .Form = $(form); // 表单 this .Folder = $(folder); // 文件控件存放空间 this .Files = []; // 文件集合 this .SetOptions(options); this .FileName = this .options.FileName; this ._FrameName = this .options.FrameName; this .Limit = this .options.Limit; this .Distinct = !! this .options.Distinct; this .ExtIn = this .options.ExtIn; this .ExtOut = this .options.ExtOut; this .onIniFile = this .options.onIniFile; this .onEmpty = this .options.onEmpty; this .onNotExtIn = this .options.onNotExtIn; this .onExtOut = this .options.onExtOut; this .onLimite = this .options.onLimite; this .onSame = this .options.onSame; this .onFail = this .options.onFail; this .onIni = this .options.onIni; if ( ! this ._FrameName){ // 为每个实例创建不同的iframe this ._FrameName = " uploadFrame_ " + Math.floor(Math.random() * 1000 ); // ie不能修改iframe的name var oFrame = isIE ? document.createElement( " <iframe name=/ "" + this._FrameName + " / " > " ) : document.createElement( " iframe " ); // 为ff设置name oFrame.name = this ._FrameName; oFrame.style.display = " none " ; // 在ie文档未加载完用appendChild会报错 document.body.insertBefore(oFrame, document.body.childNodes[ 0 ]); } // 设置form属性,关键是target要指向iframe this .Form.target = this ._FrameName; this .Form.method = " post " ; // 注意ie的form没有enctype属性,要用encoding this .Form.encoding = " multipart/form-data " ; // 整理一次 this .Ini(); }, // 设置默认属性 SetOptions: function (options) { this .options = { // 默认值 FileName: "" , // 文件上传控件的name,配合后台使用 FrameName: "" , // iframe的name,要自定义iframe的话这里设置name onIniFile: function (){}, // 整理文件时执行(其中参数是file对象) onEmpty: function (){}, // 文件空值时执行 Limit: 0 , // 文件数限制,0为不限制 onLimite: function (){}, // 超过文件数限制时执行 Distinct: true , // 是否不允许相同文件 onSame: function (){}, // 有相同文件时执行 ExtIn: [], // 允许后缀名 onNotExtIn: function (){}, // 不是允许后缀名时执行 ExtOut: [], // 禁止后缀名,当设置了ExtIn则ExtOut无效 onExtOut: function (){}, // 是禁止后缀名时执行 onFail: function (){}, // 文件不通过检测时执行(其中参数是file对象) onIni: function (){} // 重置时执行 }; Extend( this .options, options || {}); }, // 整理空间 Ini: function () { // 整理文件集合 this .Files = []; // 整理文件空间,把有值的file放入文件集合 Each( this .Folder.getElementsByTagName( " input " ), Bind( this , function (o){ if (o.type == " file " ){ o.value && this .Files.push(o); this .onIniFile(o); } })) // 插入一个新的file var file = document.createElement( " input " ); file.name = this .FileName; file.type = " file " ; file.onchange = Bind( this , function (){ this .Check(file); this .Ini(); }); this .Folder.appendChild(file); // 执行附加程序 this .onIni(); }, // 检测file对象 Check: function (file) { // 检测变量 var bCheck = true ; // 空值、文件数限制、后缀名、相同文件检测 if ( ! file.value){ bCheck = false ; this .onEmpty(); } else if ( this .Limit && this .Files.length >= this .Limit){ bCheck = false ; this .onLimite(); } else if ( !! this .ExtIn.length && ! RegExp( " /.( " + this .ExtIn.join( " | " ) + " )$ " , " i " ).test(file.value)){ // 检测是否允许后缀名 bCheck = false ; this .onNotExtIn(); } else if ( !! this .ExtOut.length && RegExp( " /.( " + this .ExtOut.join( " | " ) + " )$ " , " i " ).test(file.value)) { // 检测是否禁止后缀名 bCheck = false ; this .onExtOut(); } else if ( !! this .Distinct) { Each( this .Files, function (o){ if (o.value == file.value){ bCheck = false ; } }) if ( ! bCheck){ this .onSame(); } } // 没有通过检测 ! bCheck && this .onFail(file); }, // 删除指定file Delete: function (file) { // 移除指定file this .Folder.removeChild(file); this .Ini(); }, // 删除全部file Clear: function () { // 清空文件空间 Each( this .Files, Bind( this , function (o){ this .Folder.removeChild(o); })); this .Ini(); } } 测试代码
Code var fu = new FileUpload( " uploadForm " , " idFile " , { Limit: 3 , ExtIn: [ " jpg " , " gif " ], onIniFile: function (file){ file.value ? file.style.display = " none " : this .Folder.removeChild(file); }, onEmpty: function (){ alert( " 请选择一个文件 " ); }, onLimite: function (){ alert( " 超过上传限制 " ); }, onSame: function (){ alert( " 已经有相同文件 " ); }, onNotExtIn: function (){ alert( " 只允许上传 " + this .ExtIn.join( " , " ) + " 文件 " ); }, onFail: function (file){ this .Folder.removeChild(file); }, onIni: function (){ // 显示文件列表 var arrRows = []; 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([ " <font color='gray'>没有添加文件</font> " , " " ]); } AddList(arrRows); // 设置按钮 $( " idBtnupload " ).disabled = $( " idBtndel " ).disabled = this .Files.length <= 0 ; } }); $( " 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 = " 正在添加文件到您的网盘中,请稍候……<br />有可能因为网络问题,出现程序长时间无响应,请点击“<a href='?'><font color='red'>取消</font></a>”重新上传文件 " ; fu.Form.submit(); } // 用来添加文件列表的函数 function AddList(rows){ // 根据数组来添加列表 var FileList = $( " idFileList " ), oFragment = document.createDocumentFragment(); // 用文档碎片保存列表 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); }) // ie的table不支持innerHTML所以这样清空table while (FileList.hasChildNodes()){ FileList.removeChild(FileList.firstChild); } FileList.appendChild(oFragment); } $( " idLimit " ).innerHTML = fu.Limit; $( " idExt " ).innerHTML = fu.ExtIn.join( " , " ); $( " idBtndel " ).onclick = function (){ fu.Clear(); } // 在后台通过window.parent来访问主页面的函数 function Finish(msg){ alert(msg); location.href = location.href; } 【asp版本补充】 由于很多人问我asp版本的后台该如何写,所以决定写一个给大家。 这里我用了化境HTTP上传程序2.1版(应该是最新版了)的无组件上传类,但用的时候发现几个问题(不知是我不会用还是asp本身的问题): 1,当file控件的name是空时,后台会找不到文件; 2,文件名比较短时(例如我用"f"),后台也找不到文件; 3,当有多个file控件,如果使用相同的name,后台只会保存一个文件; 4,我在上传文件后输出的中文是乱码(有时又正常)。
针对前3条,我加了一个RanName属性,设为true的话会自动生成随机的file控件名,对于第4条,我发现如果字是直接写在文档上就不会乱码,所以我这里把输出的文字都直接写在文档上没有用变量。如果有兄弟知道怎么解决这些问题记得告诉我哦。 下载完整测试代码(.net) 下载完整测试代码(asp) 感谢由csdn网友mengshan1986提供的php和jsp版,klniuer的php修正版: 下载完整测试代码(php) 下载完整测试代码(jsp) ps:请注意程序中的文件保存路径,很多人的错误都是没有设置好文件保存路径。