<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Hopes

    Start Here..

     

    仿163網(wǎng)盤無刷新多文件上傳系統(tǒng)

    仿163網(wǎng)盤無刷新多文件上傳系統(tǒng)

    這個(gè)仿163網(wǎng)盤無刷新多文件上傳系統(tǒng),并沒有用使用.net的控件,完全的手工制作。前臺(tái)基本上是靜態(tài)的,跟后臺(tái)沒有關(guān)系,所以后臺(tái)用什么語言做都可以(后面有各個(gè)版本的實(shí)例下載)。
    本來覺得這個(gè)系統(tǒng)會(huì)很復(fù)雜,但把每個(gè)部分都分析清楚后,其實(shí)需要的技術(shù)并不高。不過當(dāng)我把各個(gè)功能函數(shù)都整理好準(zhǔn)備進(jìn)行封裝時(shí),卻發(fā)現(xiàn)要把程序封裝不是那么容易,因?yàn)槌绦蚋鷋tml的耦合度太高。然后我逐步把程序中操作html相關(guān)的部分分離出來,首先把簡單的分離,接著是文件列表,然后是file控件,最后是一些提示性程序。經(jīng)過幾次嘗試才把整個(gè)結(jié)構(gòu)封裝好,現(xiàn)在程序結(jié)構(gòu)應(yīng)該算比較清晰,有什么不明白的地方歡迎留言。


    效果預(yù)覽

    上傳文件
    添加文件:
    文件路徑
    溫馨提示:最多可同時(shí)上傳 個(gè)文件,只允許上傳 文件。
         

    這里的預(yù)覽只是前臺(tái)的效果,要整個(gè)系統(tǒng)測試請下載完整實(shí)例。

     


    程序說明

    【無刷新上傳

    要實(shí)現(xiàn)文件上傳,form必須設(shè)置幾個(gè)屬性:
    1.action:設(shè)為要處理數(shù)據(jù)的頁面地址;
    2.method:設(shè)為"post";
    3.enctype/encoding:必須設(shè)為"multipart/form-data",這里要注意的是在ie中用js修改form的enctype屬性是沒有效果的,只能修改encoding;

    后面兩個(gè)屬性程序初始化時(shí)都有設(shè)置:

    this.Form.method = "post";
    this.Form.encoding = "multipart/form-data";


    要注意這里的無刷新不是ajax哦,而是利用“古老”的iframe。
    由于ajax提交數(shù)據(jù)必須先獲取數(shù)據(jù),而js(一般情況下)是不能操作客戶端文件,要獲取文件數(shù)據(jù)就更不用說了,所以只能用iframe來做。
    先說說iframe實(shí)現(xiàn)無刷新上傳的原理:利用form的target屬性,把數(shù)據(jù)提交到頁面中一個(gè)(通常為隱藏的)iframe上直觀點(diǎn)說就是把“刷新”留給iframe。
    其實(shí)原理跟一般用iframe實(shí)現(xiàn)無刷新提交表單是一樣的,只是這里換成是文件。
    這里關(guān)鍵就是把form的target設(shè)為iframe的name:

    this.Form.target = this._FrameName;


    【iframe

    如果沒有自定義iframe,程序在初始化時(shí)會(huì)自動(dòng)創(chuàng)建無刷新所需的iframe的。
    首先必須選擇一個(gè)iframe名,這在無刷新時(shí)是必須的,為了每個(gè)實(shí)例能創(chuàng)建各自的iframe,這里用了一個(gè)隨機(jī)數(shù):

    this._FrameName = "uploadFrame_" + Math.floor(Math.random() * 1000);


    也可以用一個(gè)遞增的計(jì)算器來代替隨機(jī)數(shù)。

    接著創(chuàng)建iframe,本以為用document.createElement("iframe")創(chuàng)建再設(shè)置它的name屬性就行了。
    卻發(fā)現(xiàn)這樣設(shè)置的name在ie居然不認(rèn)(有說name是只讀屬性),還好在網(wǎng)上找到一個(gè)方法:“IE 創(chuàng)建元素,還有一個(gè)特點(diǎn),就是可以連同屬性一同創(chuàng)建”。
    例如我想給動(dòng)態(tài)創(chuàng)建的iframe設(shè)置name,可以這樣:

    document.createElement("<iframe name=\"" + this._FrameName + "\">")

    不過這個(gè)方式在ff會(huì)報(bào)錯(cuò):
    uncaught exception: String contains an invalid character (NS_ERROR_DOM_INVALID_CHARACTER_ERR)
    估計(jì)是用createElement時(shí)不能帶name,標(biāo)準(zhǔn)應(yīng)該也是這樣,所以兼容的方式這樣寫:


    var oFrame = isIE ? document.createElement("<iframe name=\"" + this._FrameName + "\">") : document.createElement("iframe");
    //為ff設(shè)置name
    oFrame.name = this._FrameName;
    oFrame.style.display 
    = "none";

    關(guān)于這方面更詳細(xì)的內(nèi)容請看這里

    創(chuàng)建完還需要插入到body中,一般的做法是使用document.body.appendChild,但在ie中會(huì)有“已終止操作”錯(cuò)誤,可以用下面這段代碼測試:


    <body>
    <div>
    <script>
    document.body.appendChild(document.createElement(
    "div"));
    </script>
    </div>
    </body>

    網(wǎng)上找到一個(gè)解析:“原來FF下的實(shí)現(xiàn)機(jī)制是當(dāng)頁面還沒有完全讀取完時(shí)body元素就已經(jīng)存在了,而IE只有頁面完全讀取結(jié)束body元素才會(huì)存在,所以在頁面中插入上面這條語句在IE下就會(huì)出現(xiàn)錯(cuò)誤”。
    我在web開發(fā)未解之謎中也提到了這個(gè)現(xiàn)象,我這里使用了insertBefore代替:

    document.body.insertBefore(oFrame, document.body.childNodes[0]);

    在服務(wù)器端文件傳送完(或失敗)之后,怎么通知客戶端呢?
    這里說說我的方法,首先我在客戶端定義一個(gè)函數(shù):

    function Finish(msg){ alert(msg); location.href = location.href; }

    很簡單,就是顯示提示并重新加載頁面(如果使用reload會(huì)導(dǎo)致ff中iframe重復(fù)加載數(shù)據(jù))。
    那服務(wù)器端如何通知客戶端的問題,就是iframe如何跟主頁面交互。
    答案是通過window.parent或window.top,在iframe中parent和top屬性“分別返回立即父窗口和最上層的祖先窗口”。
    例如我在服務(wù)器端處理完數(shù)據(jù)之后會(huì)輸出:

    context.Response.Write("<script>window.parent.Finish('" + _msg + "');</script>");

    就會(huì)執(zhí)行主頁面的Finish函數(shù)了。


    【多文件上傳】

    對于多文件上傳,這里的目的是如何做到163網(wǎng)盤那樣,只用一個(gè)file控件就實(shí)現(xiàn)多文件上傳。
    這里參考了163網(wǎng)盤的思路,下面說說如何實(shí)現(xiàn):
    首先必須有一個(gè)文件空間(我自己定的名字),例如程序中的"idFile"對象,這個(gè)空間不需要內(nèi)容甚至一個(gè)div就可以,主要是用來存放file控件,程序中Folder屬性就是這個(gè)文件空間對象。
    ps:這里的要求是把file控件都控制在文件空間里,即使不是單file控件的情況。
    再說說Files屬性,這個(gè)屬性放的是file控件集合,方便獲取file控件,在下面“文件列表”就會(huì)用到。

    處理這些file控件的程序主要在Ini函數(shù)中:
    首先是處理文件空間中的file控件:


    this.Files = [];
    //整理文件空間,把有值的file放入文件集合
    Each(this.Folder.getElementsByTagName("input"), Bind(thisfunction(o){
        
    if(o.type == "file"){ o.value && this.Files.push(o); this.onIniFile(o); }
    }))

    可以看到這里主要是把file控件放入到Files中,并執(zhí)行附加函數(shù)onIniFile,我是這樣定義這個(gè)函數(shù)的:

    onIniFile: function(file){ file.value ? file.style.display = "none" : this.Folder.removeChild(file); }

    這里為了實(shí)現(xiàn)單file控件,把原來有值的file都隱藏了,還有那個(gè)“單file控件”呢?
    別急,接著就在文件空間插入一個(gè)新的file控件:


    var file = document.createElement("input");
    file.name 
    = this.FileName; file.type = "file"; file.onchange = Bind(thisfunction(){ this.Check(file); this.Ini(); });
    this.Folder.appendChild(file);

    可以看到file控件的name是FileName屬性的值,默認(rèn)是空的,如果服務(wù)器端需要這個(gè)name的話就可以設(shè)置。
    這里可以看到每個(gè)file控件都有onchange來執(zhí)行檢測函數(shù)Check,這樣每次選擇文件后都會(huì)用Check檢測一次,這里說說這個(gè)Check函數(shù):


    //檢測變量
    var bCheck = true;
    //進(jìn)行空值、文件數(shù)、后綴名、同值檢測
    if(!file.value){
        bCheck 
    = falsethis.onEmpty();
    else if(this.Limit && this.Files.length >= this.Limit){
        bCheck 
    = falsethis.onLimite();
    else if(!!this.ExtIn.length && !RegExp("\.(" + this.ExtIn.join("|"+ ")$""i").test(file.value)){
        
    //檢測是否允許后綴名
        bCheck = falsethis.onNotExtIn();
    else if(!!this.ExtOut.length && RegExp("\.(" + this.ExtOut.join("|"+ ")$""i").test(file.value)) {
        
    //檢測是否禁止后綴名
        bCheck = falsethis.onExtOut();
    else if(!!this.Distinct) {
        Each(
    this.Files, function(o){ if(o.value == file.value){ bCheck = false; } })
        
    if(!bCheck){ this.onSame(); }
    }

    里面有一個(gè)檢測變量bCheck,然后進(jìn)行空值、文件數(shù)限制、后綴名、相同文件的檢測,當(dāng)其中一個(gè)步驟不通過bCheck就會(huì)設(shè)為false,一個(gè)常用的檢測結(jié)構(gòu)。
    這里說說檢測后綴名,由于js不能像后臺(tái)那樣獲取文件的文件類型,所以只能根據(jù)后綴名來判斷,例如用正則判斷:

    /\.(jpg|gif)$/i.test(file.value)

    這樣判斷顯然是不夠的,所以如果要做文件類型判斷的話一定要在后臺(tái)用ContentType再判斷一次。
    最后如果沒有通過檢測就會(huì)執(zhí)行onFail函數(shù):

    !bCheck && this.onFail(file);

    我在onFail函數(shù)中設(shè)定了移除沒有通過檢測的file控件:

    onFail: function(file){ this.Folder.removeChild(file); }


    這樣就基本實(shí)現(xiàn)(正確的說是模擬)了單file控件上傳多個(gè)文件的效果了。


    【文件列表】

    在上面的Ini函數(shù)中,最后執(zhí)行了一個(gè)附加函數(shù)onIni,這個(gè)函數(shù)是用戶自己定義的,我就在這個(gè)函數(shù)中添加文件列表。

    在之前先說說添加文件列表的函數(shù)AddList,這個(gè)函數(shù)是用來把file控件的值列在一個(gè)table里面。
    函數(shù)的參數(shù)是一個(gè)二維數(shù)組,其中第一維是行(tr),第二維是列(td)。
    首先獲取列表對象FileList,再定義一個(gè)文檔碎片oFragment來操作dom:

    var FileList = $("idFileList"), oFragment = document.createDocumentFragment();

    然后用兩個(gè)Each把二維數(shù)組插入到文檔碎片中:

    Code

    其中用了一個(gè)判斷if(typeof o == "string"),如果是文本就直接用innerHTML插入td,如果不是文本(這里不是文本就是一個(gè)對象)就用appendChild插入到td。
    當(dāng)數(shù)據(jù)都插入到文檔碎片,就準(zhǔn)備把文檔碎片插入到FileList中,不過還有一個(gè)步驟就是清空FileList中原有的數(shù)據(jù)。
    本來把innerHTML設(shè)為空來清空FileList會(huì)更有效率,但ie的table中只有td支持innerHTML,所以只好用removeChild來清空:

    while(FileList.hasChildNodes()){ FileList.removeChild(FileList.firstChild); }

    之后就可以把文檔碎片插入了:

    FileList.appendChild(oFragment);


    繼續(xù)看onIni函數(shù),現(xiàn)在只需要把要顯示的數(shù)據(jù)組成一個(gè)二維數(shù)組,再用AddList就能顯示文件列表了,這時(shí)存放file控件集合的Files屬性就大有用處了。
    首先定義一個(gè)放顯示數(shù)據(jù)的數(shù)組:

    var arrRows = [];

    然后根據(jù)Files對這個(gè)數(shù)組賦值:

    Code

    當(dāng)Files沒有控件時(shí)只是輸出“沒有添加文件”,有控件時(shí)就會(huì)把每個(gè)file控件的要顯示數(shù)據(jù)放到一個(gè)數(shù)組中,可以看到這個(gè)數(shù)組其實(shí)就是td內(nèi)容的集合,接著把這個(gè)數(shù)組加入到arrRows中形成二維數(shù)組,最后把得到的arrRows給AddRow函數(shù)顯示數(shù)據(jù)就行了。
    為了能取消指定的file控件,這里插入了一個(gè)a來觸發(fā)刪除函數(shù)Delete,這里也有一個(gè)技巧,這里把href設(shè)為"javascript:void(0);",并在onclick中返回false,這樣能最大程度的實(shí)現(xiàn)僅僅執(zhí)行js而不去跳轉(zhuǎn)。

    在表單提交時(shí)也要重新顯示文件列表,表單提交后就不允許刪除文件了,只顯示文件路徑就行了:

    Code

    說到表單提交要注意一個(gè)問題,就是表單是不能嵌套的,最好是把表單放到服務(wù)器表單之外,沒有辦法才使用服務(wù)器表單作為提交表單(由于程序會(huì)修改提交表單的屬性,所以盡量不要這樣使用)。

    這樣文件列表就完成了,有興趣的話也可以自己封裝一下這個(gè)功能。


    【file樣式】

    到此,程序的功能都已經(jīng)實(shí)現(xiàn)了,但在163網(wǎng)盤中還有一個(gè)特別的地方,就是file控件的樣式。
    如果有用過163網(wǎng)盤上傳文件,就知道那個(gè)file控件就像一個(gè)按鈕,但功能確實(shí)是一個(gè)file控件。
    但當(dāng)自己嘗試修改file控件的樣式時(shí),發(fā)現(xiàn)單單設(shè)置file控件的樣式并不能實(shí)現(xiàn)想要的效果。
    于是我想了另一個(gè)辦法,用一個(gè)button來模擬,結(jié)果發(fā)現(xiàn)也不行,用js根本操作不了file控件,應(yīng)該是考慮到安全問題吧。
    最后是參考了163網(wǎng)盤和muxrwc模擬126附件添加的效果,總結(jié)了這個(gè)方法:
    1.指定用一個(gè)容器(例如程序中的idFile)。
    容器最好指定高和寬,并且overflow為hidden,不是塊級(jí)元素的最好設(shè)display為block(為了高和寬的正確呈現(xiàn));
    2.在容器里放一個(gè)file控件,并設(shè)置樣式,使能觸發(fā)彈出選擇文件框的部分覆蓋整個(gè)容器,并設(shè)置成全透明。
    容器指定準(zhǔn)確的高和寬就是為了能通過file控件中不多的能設(shè)置的樣式來覆蓋整個(gè)容器;
    3.現(xiàn)在已經(jīng)把容器模擬成file控件了,可以直接設(shè)置容器的樣式來模擬設(shè)置file控件的樣式了。

    在程序中主要用file控件的margin-left和font-size來實(shí)現(xiàn)覆蓋整個(gè)容器:

    Code

    至于容器,我使用了有偽類hover的a元素(雖然CSS2中hover可以應(yīng)用于任何對象,但ie6不支持)。
    這里用了一個(gè)常用的小技巧,就是用一張圖片作為背景通過在hover時(shí)修改background-position來實(shí)現(xiàn)兩張圖片的效果:

    Code

    在點(diǎn)擊這個(gè)a時(shí)后會(huì)出現(xiàn)一個(gè)虛線框,在這里顯然不太美觀,可以把outline設(shè)為none來去掉,可是ie又不支持,在網(wǎng)上找到一個(gè)方法ie可以把hideFocus設(shè)為true來隱藏聚焦(即不顯示這個(gè)虛線框,hideFocus可以在js或html中設(shè)置,也可以通過expression放到css中:

    Code


    這樣完全模擬了163網(wǎng)盤的效果了。


    【后臺(tái)】

    前臺(tái)基本完成了,就到后臺(tái)啦。后臺(tái)的功能很簡單,就是處理傳遞過來的文件數(shù)據(jù)。
    這里像js + .Net 圖片切割系統(tǒng)那樣使用ashx文件處理IHttpHandler發(fā)送過來的數(shù)據(jù)。
    程序很簡單,就直接貼代碼了:

    Code

    這里只檢測了有無文件和文件數(shù)限制,其他檢測如文件大小等可以自己擴(kuò)展,應(yīng)該不難。
    處理完數(shù)據(jù)之后就通知客戶端:

    context.Response.Write("<script>window.parent.Finish('" + _msg + "');</script>");

    這個(gè)在上面iframe的內(nèi)容中已經(jīng)說明了。


    使用說明

    基本使用很簡單,實(shí)例化一個(gè)file對象,其中參數(shù)分別是form對象,文件空間對象:

    new FileUpload("uploadForm""idFile")

    這樣就實(shí)現(xiàn)了一個(gè)簡單的無刷新上傳文件表單。

    還可以使用這幾個(gè)屬性:
    Form//表單
    Folder//文件控件存放空間
    Files//文件集合

    更多的功能可以選擇設(shè)置這些屬性:
    屬性名:默認(rèn)值//說明
    FileName:"",//文件上傳控件的name,配合后臺(tái)使用
    FrameName:"",//iframe的name,要自定義iframe的話這里設(shè)置name
    onIniFile:function(){},//整理文件時(shí)執(zhí)行(其中參數(shù)是file對象)
    onEmpty:function(){},//文件空值時(shí)執(zhí)行
    Limit:0,//文件數(shù)限制,0為不限制
    onLimite:function(){},//超過文件數(shù)限制時(shí)執(zhí)行
    Distinct:true,//是否不允許相同文件
    onSame:function(){},//有相同文件時(shí)執(zhí)行
    ExtIn:[],//允許后綴名
    onNotExtIn:function(){},//不是允許后綴名時(shí)執(zhí)行
    ExtOut:[],//禁止后綴名,當(dāng)設(shè)置了ExtIn則ExtOut無效
    onExtOut:function(){},//是禁止后綴名時(shí)執(zhí)行
    onFail:function(){},//文件不通過檢測時(shí)執(zhí)行(其中參數(shù)是file對象)
    onIni:function(){}//重置時(shí)執(zhí)行

    使用方法可以參考實(shí)例。

    程序中提供了下面幾個(gè)方法:
    Ini 整理空間
    Check 檢測file對象
    Delete 刪除指定file
    Clear 刪除全部file


    程序代碼

    Code


    【asp版本補(bǔ)充】

    由于很多人問我asp版本的后臺(tái)該如何寫,所以決定寫一個(gè)給大家。
    這里我用了化境HTTP上傳程序2.1版(應(yīng)該是最新版了)的無組件上傳類,但用的時(shí)候發(fā)現(xiàn)幾個(gè)問題(不知是我不會(huì)用還是asp本身的問題):
    1,當(dāng)file控件的name是空時(shí),后臺(tái)會(huì)找不到文件;
    2,文件名比較短時(shí)(例如我用"f"),后臺(tái)也找不到文件;
    3,當(dāng)有多個(gè)file控件,如果使用相同的name,后臺(tái)只會(huì)保存一個(gè)文件;
    4,我在上傳文件后輸出的中文是亂碼(有時(shí)又正常)。

    針對前3條,我加了一個(gè)RanName屬性,設(shè)為true的話會(huì)自動(dòng)生成隨機(jī)的file控件名,對于第4條,我發(fā)現(xiàn)如果字是直接寫在文檔上就不會(huì)亂碼,所以我這里把輸出的文字都直接寫在文檔上沒有用變量。如果有兄弟知道怎么解決這些問題記得告訴我哦。


    下載完整測試代碼(.net)

    下載完整測試代碼(asp)

    感謝由csdn網(wǎng)友mengshan1986提供的php和jsp版,klniuer的php修正版:
    下載完整測試代碼(php)
    下載完整測試代碼(jsp)

    ps:請注意程序中的文件保存路徑,很多人的錯(cuò)誤都是沒有設(shè)置好文件保存路徑。

    其他上傳系統(tǒng):

    簡便無刷新文件上傳系統(tǒng)

    轉(zhuǎn)載請注明出處:http://www.cnblogs.com/cloudgamer/

    如有任何建議或疑問,歡迎留言討論。

    如果覺得文章不錯(cuò)的話,歡迎點(diǎn)一下右下角的推薦。

    程序中包含的js工具庫CJL.0.1.min.js,原文在這里

    分類: AspwebJavascriptAsp.net

    posted on 2012-08-19 20:39 ** 閱讀(220) 評(píng)論(0)  編輯  收藏


    只有注冊用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     

    導(dǎo)航

    統(tǒng)計(jì)

    公告

    你好!

    常用鏈接

    留言簿(2)

    隨筆檔案

    文章分類

    文章檔案

    新聞檔案

    相冊

    收藏夾

    C#學(xué)習(xí)

    友情鏈接

    搜索

    最新評(píng)論

    閱讀排行榜

    評(píng)論排行榜

    主站蜘蛛池模板: 日韩精品极品视频在线观看免费| 亚洲日韩在线视频| 亚洲国产综合精品一区在线播放| 成人免费无码大片a毛片| 成年在线观看免费人视频草莓| 国产h视频在线观看免费| 久久久高清免费视频| 国产福利在线免费| 在线免费视频一区| 国产麻豆免费观看91| 又色又污又黄无遮挡的免费视| 国产又大又粗又硬又长免费| 亚洲成A人片在线观看无码3D | 中文字幕在线免费播放| 成在人线av无码免费高潮水| a毛片免费播放全部完整| 无码国产精品一区二区免费vr| 久久永久免费人妻精品下载| 亚欧色视频在线观看免费| 在线a级毛片免费视频| 美女被免费视频网站a国产| 国产gav成人免费播放视频| 亚洲国产免费综合| 亚洲av无码一区二区乱子伦as| 亚洲视频一区网站| 亚洲精品无码中文久久字幕| 日韩一级片免费观看| 免费视频一区二区| 69式国产真人免费视频| 日本免费一本天堂在线| 亚洲午夜福利精品无码| 久久亚洲精品国产精品| 最新亚洲精品国偷自产在线| 牛牛在线精品免费视频观看| 91免费国产视频| 97视频免费在线| 亚洲国产V高清在线观看| 亚洲国产精品久久66| 亚洲第一街区偷拍街拍| 久久久WWW成人免费精品| 51在线视频免费观看视频|