本來覺得這個系統會很複雜,但把每個部分都分析清楚後,其實需要的技術並不高。不過當我把各個功能函數都整理好準備進行封裝時,卻發現要把程式封裝不是那麼容易,因為程式跟html的耦合度太高。然後我逐步把程式中操作html相關的部分分離出來,首先把簡單的分離,接著是檔案清單,然後是file控制項,最後是一些提示性程式。經過幾次嘗試才把整個結構封裝好。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=gb2312" /> <title>仿163網盤無重新整理檔案上傳系統</title> </head> <body> <style> .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(/attachment.php?aid=8332&noupdate=yes) 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*/ } </style> <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%" >添加檔案:</td> <td> </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" >溫馨提示:最多可同時上傳 <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> <script type="text/javascript"> 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(); } } 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 = "正在添加檔案到您的網盤中,請稍候……有可能因為網路問題,出現程式長時間無響應,請點擊"<font color='red'>取消</font>"重新上傳檔案"; //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; } </script> </body> </html>
[Ctrl+A 全選 注:如需引入外部Js需重新整理才能執行]
線上示範 http://img.jb51.net/online/FileUpload/FileUpload.htm
打包檔案下載 http://xiazai.jb51.net/200810/yuanma/FileUpload.rar