利用iframe無刷新上傳文件的坑

来源:http://www.cnblogs.com/li1056822533/archive/2017/02/22/6430604.html
-Advertisement-
Play Games

頁面里經常要用到文件上傳的功能,而且要求頁面不刷新,先說一下原理:頁面里放一個file控制項和submit按鈕,外面用form表單包住,給form表單加上對應的屬性值,action、method、entype、name,到這一步,能上傳文件了,但是這樣上傳文件會刷新頁面,這不是我們想要的。我們要的是文 ...


頁面里經常要用到文件上傳的功能,而且要求頁面不刷新,先說一下原理:頁面里放一個file控制項和submit按鈕,外面用form表單包住,給form表單加上對應的屬性值,action、method、entype、name,到這一步,能上傳文件了,但是這樣上傳文件會刷新頁面,這不是我們想要的。我們要的是文件上傳時不刷新頁面,那麼也簡單,在頁面里放一個iframe,設置它的寬高為0,這裡有兩個坑:

1、需要設置iframe的name值與form的target屬性值一樣,意思就是把form表單上傳文件的刷新轉嫁到iframe里去了;

2、form表單的enctype屬性值必須設置成multipart/form-data,將文件轉換成文件流供後端接收;

代碼如下:

<iframe name="fileUpload"></iframe>
<form method="post" action="xxxx" enctype="multipart/form-data" name="fileForm" target="fileUpload">
    <input type="file" class="fileInput" name="fileInput">
    <input type="submit" value="提交" />
</form>

頁面(這裡為了看到效果,就不將iframe的寬高設為0了):

事情就這麼愉快地結束了嗎?當然沒有,離國慶節還有那麼些天,不要著急。

到這裡文件能上傳了,頁面也不會刷新,那麼還差什麼?當然是精益求精--優化啦。怎麼優化?假如頁面里有三個地方需要上傳不同類型的文件,最好的辦法肯定不是在頁面里將代碼copy三份,然後就這樣用,這是普通開發的做法,我們可以利用js動態生成上面這些代碼,需要上傳文件的地方,一個函數加參數就搞定了,代碼如下:

複製代碼
/*2014年9月18日17:39:47 By 王美建*/
function ajaxUpload(opt){
    /*
        參數說明:
        opt.frameName : iframe的name值;
        opt.url : 文件要提交到的地址;
        opt.fileName : file控制項的name;
        opt.format : 文件格式,以數組的形式傳遞,如['jpg','png','gif','bmp'];
        opt.callBack : 上傳成功後回調;
    */
    var iName=opt.frameName; //太長了,變短點
    var iframe,form;
    //創建iframe和form表單
    iframe = $('<iframe name="'+iName+'" />');
    form = $('<form method="post" style="display:none;" target="'+iName+'" action="'+opt.url+'"  name="form_'+iName+'" enctype="multipart/form-data" />');
    file = $('<input type="file" name="'+opt.fileName+'" />');
    file.appendTo(form);
    //插入body
    $(document.body).append(iframe).append(form);
    //觸發瀏覽事件,選擇文件
    file.click();
    //選中文件後,驗證文件格式是否符合要求
    file.change(function(){
        //取得所選文件的擴展名
        var fileFormat=$(this).val().exec(/\.[a-zA-Z]+$/)[0].substring(1);
        if(opt.format.join('-').indexOf(fileVal)!=-1){
            form.submit();//格式通過驗證後提交表單;
        }else{
            iframe.remove();
            form.remove();
            alert('文件格式錯誤,請重新選擇!');
        }
    });
    //文件提交完後
    iframe.load(function(){
        var data = $(this).contents().find('body').html();
        opt.callBack(data);
        iframe.remove();
        form.remove();
    })
}
複製代碼
使用方法:在頁面里放一個按鈕Btn,點擊Btn時觸發ajaxUpload方法,ajaxUpload方法內部自動創建上傳所需要的元素並自動觸發file.click()事件供用戶選擇文件,選中文件後自動驗證文件格式並提交,然後返回後端返回的結果,到這裡,問題解決了80%,為什麼不是100%?ajaxUpload方法在IE8以上及火狐、chrome瀏覽器都沒有問題,但在IE8及以下的瀏覽器上傳文件會提示:沒有許可權!這是因為低版本的IE做了安全限制,file控制項必須由用戶主動點擊觸發選擇的文件才可以上傳,而不能使用js的click事件來模擬點擊觸發。在此我又想說,IE我~!@#¥%……&*()——……。
辦法總比困難多,既然一定要由用戶點擊來觸發,那麼直接把頁面里的按鈕替換成file控制項吧,iframe和form還是動態創建,當用戶點擊file控制項選擇文件後,會觸發file控制項的chang事件,給file控制項的change事件綁定ajaxUpload方法並將file控制項的id傳進去,ajaxUpload方法通過id獲取file控制項並將file控制項appendTo到動態創建的form里,之後的步驟與上面無異——驗證格式→提交表單→觸發回調。細心的同學會發現,選擇文件後,file控制項會appendTo到form表單里,那頁面里放file控制項的地方不是空了麽?並且,表單提交後,file會隨著form一起被remove掉,所以,在file控制項appendTo到form前,先建一個變數P將file控制項的父級存起來,form表單提交之後,先將file控制項appendTo回到P裡面,當然,file控制項appendTo到form時,file控制項依然會在頁面里消失,所以頁面里的Btn要保留,把file控制項定位在Btn上面,透明度設置成0,這樣點擊Btn實際上點擊的是蓋在上面的file控制項,這樣即使file控制項被appendTo到form裡面,用戶也不會察覺到什麼變化,問題迎刃而解!相容的寫法如下:
複製代碼
/*2014年9月19日11:11:07 By 王美建*/
function ajaxUpload(opt){ /* 參數說明: opt.id : 頁面里file控制項的ID; opt.frameName : iframe的name值; opt.url : 文件要提交到的地址; opt.format : 文件格式,以數組的形式傳遞,如['jpg','png','gif','bmp']; opt.callBack : 上傳成功後回調; */ var iName=opt.frameName; //太長了,變短點 var iframe,form,file,fileParent; //創建iframe和form表單 iframe = $('<iframe name="'+iName+'" />'); form = $('<form method="post" style="display:n1one;" target="'+iName+'" action="'+opt.url+'" name="form_'+iName+'" enctype="multipart/form-data" />'); file = $('#'+opt.id); //通過id獲取flie控制項 fileParent = file.parent(); //存父級 file.appendTo(form); //插入body $(document.body).append(iframe).append(form); //取得所選文件的擴展名 var fileFormat=/\.[a-zA-Z]+$/.exec(file.val())[0].substring(1); if(opt.format.join('-').indexOf(fileFormat)!=-1){ form.submit();//格式通過驗證後提交表單; }else{ file.appendTo(fileParent); //將file控制項放回到頁面 iframe.remove(); form.remove(); alert('文件格式錯誤,請重新選擇!'); }; //文件提交完後 iframe.load(function(){ var data = $(this).contents().find('body').html(); file.appendTo(fileParent); iframe.remove(); form.remove(); opt.callBack(data); }) }
複製代碼
國際慣例,到這裡,方法已經接近完美了,為什麼是接近?來看一張圖片:


結構代碼:
.fileInput{ position: absolute;left: 0;top: 0;height: 30px; filter:alpha(opacity=60);opacity:0.6; background-color: transparent;}
.btn{width: 200px;height: 30px; margin: 100px auto; background-color: yellow; text-align: center; line-height: 30px; overflow: hidden; display: block; position: relative;}
<div class="btn">選擇文件<input type="file" class="fileInput" name="fileInput"></div>

這就是放在頁面里的file控制項,外面用一個div包住,在IE10及以下瀏覽器中,用戶單擊紅色框部分是不會彈出文件選擇框的,必須單擊藍色部分或雙擊紅色部分才行,要讓藍色部分占滿外面的div怎麼做到呢?用css設置寬度只會增加紅色部分的寬度,這時我們會發現藍色部分是有字的,對,可以通過設置font-size來使藍色部分變寬,然後給file控制項加上dir="rtl",這會讓瀏覽按鈕移到左邊,再給.btn加上overflow:hidden,可以發現瀏覽按鈕已經占滿整個div了,如下圖:


到這裡才真正完成了100%,最後,我們還可以給file控制項設置accept屬性,限制可選文件格式(IE8及以下不支持該屬性),別忘了把file控制項的透明的改為0。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • PHP驗證 第一步:先獲取表單傳送過來的內容; $_POST['']; //用這個函數來獲取表單的數據,POST必須大寫,中括弧裡面必須有單引號。 第二步:判斷 1判斷是否為正常提交: isset(); //用這個函數來判斷是否設置(存在) 例:if(isset($_POST['username'] ...
  • Scala入門 【1】 轉載請註明出處: "http://www.cnblogs.com/BYRans/" 1 基礎 val定義的為常量,var為變數 val name:Type = ,變數名後加冒號,然後定義變數類型 Scala有7種 數值類型 :Byte、Char、Short、Int、Long、 ...
  • 第13章 類繼承 13.11 編程練習 第二題 1頭文件源碼:"classic.h" 2 頭文件實現: ...
  • 用自定義的類型作為HashMap的key,必須同時重載hashCode()和equals(),才可以實現在HashMap中的查找自定義鍵。 ...
  • java用eclipse寫的,先記住幾個快捷鍵,"alt+/"調出整個函數,Ctrl+1 修改錯誤,Ctrl+shift+F 規範代碼,讓代碼看起來更好看 首先位java的結構圖 然後是第一種代碼(第一種完全在主函數中編寫): 第二種代碼將某些功能寫成一塊一塊的函數: 第三種為偷懶的辦法,從主函數開 ...
  • 電腦:W7+64位,QT:5_7_0(vs2015版本) 用QTcreator進行線上調試時出現找不到“engine。。。”,原因是沒有線上調試軟體 CDB下載地址:http://msdn.microsoft.com/zh-cn/library/windows/hardware/ff551063 安 ...
  • /* 計算球體積 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 151765 Accepted Submission(s): 60772 Pr ...
  • 參考文章:http://blog.sina.com.cn/s/blog_59ca2c2a0100qhjx.html java參數有值類型和引用類型兩種。所以java參數的傳值也就從這兩個方面分析。 從記憶體模型來說參數傳遞更為直觀一些,這裡涉及到兩種類型的記憶體:棧記憶體(stack)和堆記憶體(heap) ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...