[转]仿163网盘无刷新文件上传系统
?原文鏈接:http://www.cnblogs.com/cloudgamer/archive/2008/10/20/1314766.html
這個仿163網盤無刷新文件上傳系統,并沒有用使用.net的控件,完全的手工制作。前臺基本上是靜態的,跟后臺沒有關系,所以后臺用什么語言做都可以(后面有各個版本的實例下載)。
本來覺得這個系統會很復雜,但把每個部分都分析清楚后,其實需要的技術并不高。不過當我把各個功能函數都整理好準備進行封裝時,卻發現要把程序封裝不是那么容易,因為程序跟html的耦合度太高。然后我逐步把程序中操作html相關的部分分離出來,首先把簡單的分離,接著是文件列表,然后是file控件,最后是一些提示性程序。經過幾次嘗試才把整個結構封裝好,現在程序結構應該算比較清晰,有什么不明白的地方歡迎留言。
效果預覽
| 上傳文件 | |||||
| 添加文件: | |||||
| |||||
| 溫馨提示:最多可同時上傳 3個文件,只允許上傳 jpg,gif文件。 | |||||
| ??? | |||||
這里的預覽只是前臺的效果,要整個系統測試請下載完整實例。
程序說明
【無刷新上傳】
要實現文件上傳,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:
【iframe】
如果沒有自定義iframe,程序在初始化時會自動創建無刷新所需的iframe的。
首先必須選擇一個iframe名,這在無刷新時是必須的,為了每個實例能創建各自的iframe,這里用了一個隨機數:
也可以用一個遞增的計算器來代替隨機數。
接著創建iframe,本以為用document.createElement("iframe")創建再設置它的name屬性就行了。
卻發現這樣設置的name在ie居然不認(有說name是只讀屬性),還好在網上找到一個方法:“IE 創建元素,還有一個特點,就是可以連同屬性一同創建”。
例如我想給動態創建的iframe設置name,可以這樣:
不過這個方式在ff會報錯:
uncaught exception: String contains an invalid character (NS_ERROR_DOM_INVALID_CHARACTER_ERR)
估計是用createElement時不能帶name,標準應該也是這樣,所以兼容的方式這樣寫:
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中會有“已終止操作”錯誤,可以用下面這段代碼測試:
<body>
<div>
<script>
document.body.appendChild(document.createElement("div"));
</script>
</div>
</body>
網上找到一個解析:“原來FF下的實現機制是當頁面還沒有完全讀取完時body元素就已經存在了,而IE只有頁面完全讀取結束body元素才會存在,所以在頁面中插入上面這條語句在IE下就會出現錯誤”。
我在web開發未解之謎中也提到了這個現象,我這里使用了insertBefore代替:
在服務器端文件傳送完(或失敗)之后,怎么通知客戶端呢?
這里說說我的方法,首先我在客戶端定義一個函數:
很簡單,就是顯示提示并重新加載頁面(如果使用reload會導致ff中iframe重復加載數據)。
那服務器端如何通知客戶端的問題,就是iframe如何跟主頁面交互。
答案是通過window.parent或window.top,在iframe中parent和top屬性“分別返回立即父窗口和最上層的祖先窗口”。
例如我在服務器端處理完數據之后會輸出:
就會執行主頁面的Finish函數了。
【多文件上傳】
對于多文件上傳,這里的目的是如何做到163網盤那樣,只用一個file控件就實現多文件上傳。
這里參考了163網盤的思路,下面說說如何實現:
首先必須有一個文件空間(我自己定的名字),例如程序中的"idFile"對象,這個空間不需要內容甚至一個div就可以,主要是用來存放file控件,程序中Folder屬性就是這個文件空間對象。
ps:這里的要求是把file控件都控制在文件空間里,即使不是單file控件的情況。
再說說Files屬性,這個屬性放的是file控件集合,方便獲取file控件,在下面“文件列表”就會用到。
處理這些file控件的程序主要在Ini函數中:
首先是處理文件空間中的file控件:
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控件:
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函數:
//檢測變量
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不能像后臺那樣獲取文件的文件類型,所以只能根據后綴名來判斷,例如用正則判斷:
這樣判斷顯然是不夠的,所以如果要做文件類型判斷的話一定要在后臺用ContentType再判斷一次。
最后如果沒有通過檢測就會執行onFail函數:
我在onFail函數中設定了移除沒有通過檢測的file控件:
onFail:?function(file){?this.Folder.removeChild(file);?}
這樣就基本實現(正確的說是模擬)了單file控件上傳多個文件的效果了。
【文件列表】
在上面的Ini函數中,最后執行了一個附加函數onIni,這個函數是用戶自己定義的,我就在這個函數中添加文件列表。
在之前先說說添加文件列表的函數AddList,這個函數是用來把file控件的值列在一個table里面。
函數的參數是一個二維數組,其中第一維是行(tr),第二維是列(td)。
首先獲取列表對象FileList,再定義一個文檔碎片oFragment來操作dom:
然后用兩個Each把二維數組插入到文檔碎片中:
CodeEach(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來清空:
之后就可以把文檔碎片插入了:
FileList.appendChild(oFragment);
繼續看onIni函數,現在只需要把要顯示的數據組成一個二維數組,再用AddList就能顯示文件列表了,這時存放file控件集合的Files屬性就大有用處了。
首先定義一個放顯示數據的數組:
然后根據Files對這個數組賦值:
Codeif(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來實現覆蓋整個容器:
Codea.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中:
Codea.files,?a.files?input?{
????outline:none;/*ff*?/
????hide-focus:expression(this.hideFocus=true);/*ie*?/
}
這樣完全模擬了163網盤的效果了。
【后臺】
前臺基本完成了,就到后臺啦。后臺的功能很簡單,就是處理傳遞過來的文件數據。
這里像js + .Net 圖片切割系統那樣使用ashx文件處理IHttpHandler發送過來的數據。
程序很簡單,就直接貼代碼了:
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;
????????????}
????????}
????}
}
這里只檢測了有無文件和文件數限制,其他檢測如文件大小等可以自己擴展,應該不難。
處理完數據之后就通知客戶端:
這個在上面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
完整程序
樣式設置
.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>
程序代碼
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();
??}
}
測試代碼
Codevar?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版:
下載完整測試代碼(php)
下載完整測試代碼(jsp)
ps:請注意程序中的文件保存路徑,很多人的錯誤都是沒有設置好文件保存路徑。
轉載于:https://www.cnblogs.com/scgw/archive/2008/11/17/1334789.html
總結
以上是生活随笔為你收集整理的[转]仿163网盘无刷新文件上传系统的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 进军中国软件,踏上寻找自我价值之路的菜鸟
- 下一篇: 正确获取get参数