前端文件上傳方式

?一丶前端文件上傳方式

前端網頁文件上傳一般使用 <input type="file" />來實現。

? ? 在 HTML 文檔中: `<input type="file" />`標簽每出現一次,一個 FileUpload 對象就會被創建。該標簽包含一個文本輸入字段,用來輸入文件名,還有一個按鈕,用來打開文件選擇對話框以便圖形化選擇文件,該標簽的 value屬性保存了用戶指定的文件的名稱。

? ? ? ? ? ? ? ? ? ? ? 多選: 標簽可以通過添加 multiple 屬性來支持多選;如果選擇了多個文件, 這個值表示第一個被選擇的文件路徑. JavaScript 可以通過 Input 的 FileList屬性獲取到其他的文件路徑.

? ? ? ? ? ? ? ? 文件信息:可以通過 input.files 屬性返回 — 返回值是一個 FileList 對象,這個對象是一個包含了許多 File 文件的列表,列表包含圖片的name,type,size? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 等屬性。

? ? ? ? 限制文件類型:你可以使用 input 的 accept 屬性,accept 屬性接受一個逗號分隔的 MIME 類型字符串。如: accept="image/png, image/jpeg" or accept=".png, .jpg, .jpeg" — PNG/JPEG

? ? ? ? ? ? ? ? 選擇文件:會觸發input的onchange事件;

? ? ? ? ? ? ? ? ? ? ? 上傳:上傳文件前 使用FileReader對象讀取指定file的文件,并將文件轉換為二進制字符串, 并將xhr對象, overrideMimeType 屬性設置為text/plain;? charset=x-user-defined-binary, 最終后臺接收到二進制后再做具體處理。

?第一種:經典的form和input上傳

設置form的aciton為后端頁面,必填項:enctype="multipart/form-data",type=‘post’

? ? <form action='uploadFile.php' enctype="multipart/form-data" type='post'>

? ?   <input type='file'>

? ?   <input type='hidden' name='userid'>

? ?   <input type='hidden' name='signature'>

? ?   <button>提交</button>

? ? </form>

使用input選擇文件,設置好其他input的值,點擊提交,將文件數據及簽名等認證信息發送到form設置的action對應的頁面,瀏覽器也會跳轉到該頁面。觸發form表單提交數據的方式有2種,一種是在頁面上點擊button按鈕或<input type='submit'>按鈕觸發,第二種是在js中執行form.submit()方法。

優點:使用簡單方便,兼容性好,基本所有瀏覽器都支持。

缺點: 1. 提交數據后頁面會跳轉(下面會講如何禁止頁面跳轉)。

? ? 2.因為是瀏覽器發起的請求,不是一個ajax,所以前端無法知道什么時候上傳結束。

? ? ? 3. form表單里發送除文件外的數據,一般是新建一個type=hidden的input,value=‘需要傳的數據’,每發送一個數據就需要一個input,一旦多了就會使得dom看起來比較冗余。

小技巧:

form表單提交數據后會自動跳轉到action指定的頁面,為了禁止頁面跳轉,可以在頁面中新建一個空的ifame,比如name='upload',然后設置form的target="Uploader",form有一個target的屬性,規定在何處打開action,這樣form提交數據后就會仍停留在當前頁。代碼如下:

? ? <form action='uploadFile.url' enctype="multipart/form-data" type='post' target="uploaderPage">

? ? ???? <input type='file'>

? ? ????button>提交</button>

? ? </form>

? ? <ifrmae name='upload' id='uploaderPage'></iframe>

這樣寫的另一個好處是,可以知道什么時候上傳完成并接收到后端的回調結果。比如上面這個例子,文件數據發送到了 'uploadFile.url',假設該頁面處理完數據后返回了一個地址,該地址會被寫入到之前的iframe中。所以在ifame的onload函數觸發時,也就是上傳完成后,可以在iframe中讀取到后端返回的數據。

? ? var iframe = document.getElementById('uploadPage');

? ? iframe.onload = function () {

? ? ???? var doc = window.frames['uploaderPage'].document;

? ? ???? var pre = doc.getElementsByTagName('pre');

? ? ???? var obj = JSON.parse(pre[0].innerHTML);

? ? }

使用這種方法時需要注意,iframe有跨域限制,創建出來的iframe的地址如果和當前頁面地址不同源,會報錯。這種情況下,建議大家在iframe的onload函數中,再次向后端請求一個接口獲取文件地址,而不是直接去iframe里讀取。或者返回這樣的數據。

? ? <script type="text/javascript">

? ? ???? window.top.window.callback(data)

? ? </script>

callback是和前端約定好的名字,上傳完成后觸發該函數并返回后端數據。

?第二種:使用formData上傳。(分借用form和不借用form)

? 借助form的ajax文件上傳

? ? <script src="jquery.min.js"></script>

? ? <form id="uploadForm" enctype="multipart/form-data">

? ? ? ? <input type="file" name="file" id="file">

? ? ? ? <input type="button" value="Upload" id="upload" />

? ? </form>

? ? <script>

? ? ? ? $(function () {

? ? ? ? ? ? $('#upload').click(function () {

? ? ? ? ? ? ? ? $.ajax({

? ? ? ? ? ? ? ? ? ? url: "http://localhost:8080/img",

? ? ? ? ? ? ? ? ? ? type: "post",

? ? ? ? ? ? ? ? ? ? data: new FormData($('#uploadForm')[0]),

? ? ? ? ? ? ? ? ? ? cache: false,

? ? ? ? ? ? ? ? ? ? processData: false,

? ? ? ? ? ? ? ? ? ? contentType: false,

? ? ? ? ? ? ? ? ? ? success: function (res) {

? ? ? ? ? ? ? ? ? ? console.log(res)

? ? ? ? ? ? ? ? ? ? },

? ? ? ? ? ? ? ? ? ? error: function (err) {

? ? ? ? ? ? ? ? ? ? ? ? console.log(err)

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? })

? ? ? ? ? ? })

? ? ? ? })

? ? </script>

processData設置為false。因為data值是FormData對象,不需要對數據做處理。

`<form>`標簽添加enctype="multipart/form-data"屬性。

cache設置為false,上傳文件不需要緩存。

contentType設置為false。因為是由`<form>`表單構造的FormData對象,且已經聲明了屬性enctype="multipart/form-data",所以這里設置為false。

不借助form的ajax文件上傳

? ? <input type="file" name="file" id="file"><input type="button" value="Upload" id="upload" />

? ? <script src="jquery.min.js"></script>

? ? <script>

? ? $(function () {

? ? ? ? $('#upload').click(function () {

? ? ? ? ? ? let file = $("#file")[0].files[0];

? ? ? ? ? ? //創建formdata對象

? ? ? ? ? ? let formData = new FormData();

? ? ? ? ? ? formData.append("file", file);

? ? ? ? ? ? $.ajax({

? ? ? ? ? ? ? ? url: "http://localhost:8081/images",

? ? ? ? ? ? ? ? type: "post",

? ? ? ? ? ? ? ? data: formData,

? ? ? ? ? ? ? ? cache: false,

? ? ? ? ? ? ? ? processData: false,

? ? ? ? ? ? ? ? contentType: false,

? ? ? ? ? ? ? ? // headers: { 'Content-Type': 'multipart/form-data' },

? ? ? ? ? ? ? ? success: function (res) {

? ? ? ? ? ? ? ? ? ? console.log(res)

? ? ? ? ? ? ? ? },

? ? ? ? ? ? ? ? error: function (err) {

? ? ? ? ? ? ? ? ? ? console.log(err)

? ? ? ? ? ? ? ? }

? ? ? ? ? ? })

? ? ? })

? ? })

? ? </script>

append()的第二個參數應是文件對象,即`$('#file')[0].files[0]`。

contentType也要設置為‘false’。

從代碼`$('#file')[0].files[0]`中可以看到一個`<input type="file">`標簽能夠上傳多個文件, 只需要在`<input type="file">`里添加multiple或multiple="multiple"屬性。

用js構造form表單的數據,簡單高效,但最低只兼容IE10,所以需要兼容IE9的童鞋們就略過這個方法吧。


? ? ? html:

? ? ? ? <input type='file'>

? ? ? ? js:

? ? ? ? var formData = new FormData();

? ? ? ? formData.append("userid", userid);

? ? ? ? formData.append("signature", signature);

? ? ? ? formData.append("file", file); //file是blob數據

?????//再用ajax發送formData到服務器即可,注意一定要是post方式上傳

說明:第一種方法提到了創建多個type=‘hidden’的input來發送簽名數據,這兒可以用formData.append方法來代替該操作,避免了dom中有多個input的情況出現。最后將file數據也append到formData發送到服務器即可完成上傳。

優點:由于這種方式是ajax上傳,可以準確知道什么時候上傳完成,也可以方便地接收到回調數據。

缺點:兼容性差

第三種:使用fileReader讀取文件數據進行上傳。

HTML5的新api,兼容性也不是特別好,只兼容到了IE10。

? ? var fr = new FileReader();

? ? fr.readAsDataURL(file);

? ? fr.onload = function (event) {

? ? var data= event.target.result; //此處獲得的data是base64格式的數據

? ? ? ? ? ? ? ? ? ? ? ? img.src = data;

? ? ajax(url,{data} ,function(){})

? ? }

上面獲得的data可以用來實現圖片上傳前的本地預覽,也可以用來發送base64數據給后端然后返回該數據塊對應的地址。

優點: 同第二種

缺點:一次性發送大量的base64數據會導致瀏覽器卡頓,服務器端接收這樣的數據可能也會出現問題

第四種:flash上傳 參考jQuery封裝好的uploadify插件

? ? <div id="file_upload"></div>

html部分很簡單,預留一個hook后,插件會在這個節點內部創建Flash的object,并且還附帶創建了上傳進度、取消控件和多文件隊列展示等界面。

? ? $(function() {

? ? $("#file_upload").uploadify({

? ???? auto: true,

????? method: "Post",

????? width: 120,

? ???? height: 30,

? ???? swf: './uploadify.swf',

? ? ???? uploader: 'http://uploadUrl',

? formData: {

? ???? token: $("#token").val()

? ? },

? ? fileObjName: "file",

? ? onUploadSuccess: function(file, data, response){

? ? // 根據返回結果指定界面操作

? ? }

? ? });

? ? });

關于jQuery.uploadify可以訪問了解: http://www.uploadify.com/documentation/ 。值得注意的是flash并不適合手機端應用,更好的解決方案是使用flash+html5來解決平臺的兼容性問題。

二丶圖片上傳和預覽

?方法一:使用js的FileReader對象

1、FileReader對象簡介

1.檢測瀏覽器對FileReader的支持

? ? if(window.FileReader) {

? ? ???? var fr = new FileReader();

? ????? // add your code here

? ? }else {

? ????? alert("Not supported by your browser!");

? ? }

調用FileReader對象的方法

FileReader 的實例擁有 4 個方法,其中 3 個用以讀取文件,另一個用來中斷讀取。下面的表格列出了這些方法以及他們的參數和功能,

需要注意的是 ,無論讀取成功或失敗,方法并不會返回讀取結果,這一結果存儲在 result屬性中。

? ? 方法名? ? ? ? ? ? ? ? ????????? 參數? ? ? ? ? ? ????????? 描述

? ? abort? ? ? ? ? ? ? ? ????????? ????none? ? ? ? ? ????????? 中斷讀取

? ? readAsBinaryString ? ???? file? ? ? ? ? ? ? ? ? ? ? ?將文件讀取為二進制碼

? ? readAsDataURL ????? ???? file ? ???????????? ???????? 將文件讀取為 DataURL

? ? readAsText ? ????????????????file, [encoding] ???????? 將文件讀取為文本

readAsText:該方法有兩個參數,其中第二個參數是文本的編碼方式,默認值為 UTF-8。這個方法非常容易 ?

理解,將文件以文本方式讀取,讀取的結果即是這個文本文件中的內容。

readAsBinaryString:該方法將文件讀取為二進制字符串,通常我們將它傳送到后端,后端可以通過這段字符串存儲文件。

readAsDataURL:這是例子程序中用到的方法,該方法將文件讀取為一段以 data: 開頭的字符串,這段字符 串的實質就是 Data URL,Data URL是一種將小文件直接嵌入文檔的方案。這里的小文件通常是指圖像與 html 等格式的文件。(其中base64的方式就是由此來獲得的。。)

2. FileReader處理事件簡介

FileReader 包含了一套完整的事件模型,用于捕獲讀取文件時的狀態,下面這個表格歸納了這些事件。

onabort? ? ? ? 中斷時觸發

onerror? ? ? ? ? 出錯時觸發

onload? ? ? ? ? 文件讀取成功完成時觸發

onloadend? ? 讀取完成觸發,無論成功或失敗

onloadstart? ? 讀取開始時觸發

onprogress? ? 讀取中

文件一旦開始讀取,無論成功或失敗,實例的 result 屬性都會被填充。如果讀取失敗,則 result 的值為 null ,否則即是讀取的結果,絕大多數的程序都會在成功讀取文件的時候,抓取這個值。

<p>

? ? ? ? ? ? <label>請選擇一個文件:</label>

? ? ? ? ? ? <input type="file" id="file" />

? ? ? ? ? ? <input type="button" value="讀取圖像" onclick="readAsDataURL()" />

? ? ? ? ? ? <input type="button" value="讀取二進制數據" onclick="readAsBinaryString()" />

? ? ? ? ? ? <input type="button" value="讀取文本文件" onclick="readAsText()" />

? ? ? ? </p>

? ? ? ? <div id="result" name="result"></div>

? ? ? ? <script type="text/javascript">

? ? ? ? ? ? var result = document.getElementById("result");

? ? ? ? ? ? var file = document.getElementById("file");

? ? ? ? ? ? //判斷瀏覽器是否支持FileReader接口

? ? ? ? ? ? if (typeof FileReader == 'undefined') {

? ? ? ? ? ? ? ? result.InnerHTML = "<p>你的瀏覽器不支持FileReader接口!</p>";

? ? ? ? ? ? ? ? //使選擇控件不可操作

? ? ? ? ? ? ? ? file.setAttribute("disabled", "disabled");

? ? ? ? ? ? }

? ? ? ? ? ? function readAsDataURL() {

? ? ? ? ? ? ? ? //檢驗是否為圖像文件

? ? ? ? ? ? ? ? var file = document.getElementById("file").files[0];

? ? ? ? ? ? ? ? if (!/image\/\w+/.test(file.type)) {

? ? ? ? ? ? ? ? ? ? alert("看清楚,這個需要圖片!");

? ? ? ? ? ? ? ? ? ? return false;

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? var reader = new FileReader();

? ? ? ? ? ? ? ? //將文件以Data URL形式讀入頁面

? ? ? ? ? ? ? ? reader.readAsDataURL(file);

? ? ? ? ? ? ? ? reader.onload = function (e) {

? ? ? ? ? ? ? ? ? ? var result = document.getElementById("result");

? ? ? ? ? ? ? ? ? ? //顯示文件

? ? ? ? ? ? ? ? ? ? result.innerHTML = '<img src="' + this.result + '" alt="" />';

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? ? ? function readAsBinaryString() {

? ? ? ? ? ? ? ? var file = document.getElementById("file").files[0];

? ? ? ? ? ? ? ? var reader = new FileReader();

? ? ? ? ? ? ? ? //將文件以二進制形式讀入頁面

? ? ? ? ? ? ? ? reader.readAsBinaryString(file);

? ? ? ? ? ? ? ? reader.onload = function (f) {

? ? ? ? ? ? ? ? ? ? var result = document.getElementById("result");

? ? ? ? ? ? ? ? ? ? //顯示文件

? ? ? ? ? ? ? ? ? ? result.innerHTML = this.result;

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? ? ? function readAsText() {

? ? ? ? ? ? ? ? var file = document.getElementById("file").files[0];

? ? ? ? ? ? ? ? var reader = new FileReader();

? ? ? ? ? ? ? ? //將文件以文本形式讀入頁面

? ? ? ? ? ? ? ? reader.readAsText(file);

? ? ? ? ? ? ? ? reader.onload = function (f) {

? ? ? ? ? ? ? ? ? ? var result = document.getElementById("result");

? ? ? ? ? ? ? ? ? ? //顯示文件

? ? ? ? ? ? ? ? ? ? result.innerHTML = this.result;

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? </script>

3 、使用js的FileReader對象實現上傳圖片時的圖片預覽功能

? ? <!DOCTYPE html>

? ? <html>


? ? <head>

? ? ? ? <meta name="viewport" content="width=device-width,initial-scale=1, user-scalable=no">

? ? ? ? <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

? ? ? ? <meta name="format-detection" content="telephone=no">

? ? ? ? <title>test</title>

? ? ? ? <script>

? ? ? ? ? ? //選擇圖片時預覽功能

? ? ? ? ? ? function imageshow(source) {

? ? ? ? ? ? ? ? var file = source.files[0];

? ? ? ? ? ? ? ? var imageid = source.id;

? ? ? ? ? ? ? ? if (window.FileReader) {

? ? ? ? ? ? ? ? ? ? var fr = new FileReader();

? ? ? ? ? ? ? ? ? ? fr.onloadend = function (e) {

? ? ? ? ? ? ? ? ? ? ? ? document.getElementById("portrait" + imageid).src = e.target.result;

? ? ? ? ? ? ? ? ? ? };

? ? ? ? ? ? ? ? ? ? fr.readAsDataURL(file);

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? document.getElementById("image" + imageid).style.display = "none";

? ? ? ? ? ? ? ? document.getElementById("show" + imageid).style.display = "block";

? ? ? ? ? ? }

? ? ? ? </script>

? ? </head>


? ? <body>

? ? ? ? <div>

? ? ? ? ? ? <div id="image1">

? ? ? ? ? ? ? ?       <p>上傳截圖</p>

? ? ? ? ? ? ? ? <input type="file" name="screenshot1" id="1" onchange="imageshow(this)" />

? ? ? ? ? ? </div>

? ? ? ? ? ?     <div id="show1" style="display:none;">

? ? ? ? ? ? ? ?       <img src="" id="portrait1" width="100" height="70">

? ? ? ? ? ? ? ?     </div>

? ? ? ? ? ?     <div id="image2">

? ? ? ? ? ? ? ? <p>上傳截圖</p>

? ? ? ? ? ? ? ? <input type="file" name="screenshot2" id="2" onchange="imageshow(this)" />

? ? ? ? ? ? </div>

? ? ? ? ? ?     <div id="show2" style="display:none;">

? ? ? ? ? ? ? ?       <img src="" id="portrait2" width="100" height="70">

? ? ? ? ? ? ? ?    </div>

? ? ? ? ? ? <div id="image3">

? ? ? ? ? ? ? ? <p>上傳截圖</p>

? ? ? ? ? ? ? ? <input type="file" name="screenshot3" id="3" onchange="imageshow(this)" />

? ? ? ? ? ? </div>

? ? ? ? ? ?   <div id="show3" style="display:none;">

? ? ? ? ? ? ? ?       <img src="" id="portrait3" width="100" height="70">

? ? ? ? ? ? ? ?     </div>

? ? ? ? </div>

? ? </body>


? ? </html>

方法二:使用window.createObjectURL

直接上代碼:

? ? <!DOCTYPE html>

? ? <html>


? ? <head>

? ? ? ? <title>圖片上傳預覽</title>

? ? ? ? <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

? ? ? ? <script src="http://www.codefans.net/ajaxjs/jquery-1.6.2.min.js"></script>

? ? </head>


? ? <body>

? ? ? ? <form name="form0" id="form0">

? ? ? ? ? ? <input type="file" name="file0" id="file0" multiple="multiple" />

? ? ? ? ? ? <br>

? ? ? ? ? ? <img src="" width="100" height="100" id="img0">

? ? ? ? </form>

? ? ? ? <script>

? ? ? ? ? ? $("#file0").change(function () {

? ? ? ? ? ? ? ? var objUrl = getObjectURL(this.files[0]);

? ? ? ? ? ? ? ? console.log("objUrl = " + objUrl);

? ? ? ? ? ? ? ? if (objUrl) {

? ? ? ? ? ? ? ? ? ? $("#img0").attr("src", objUrl);

? ? ? ? ? ? ? ? }

? ? ? ? ? ? });


? ? ? ? ? ? //取得該文件的url function getObjectURL(file) {

? ? ? ? ? ? var url = null;

? ? ? ? ? ? if (window.createObjectURL != undefined) {

? ? ? ? ? ? ? ? url = window.createObjectURL(file);

? ? ? ? ? ? } else if (window.URL != undefined) {

? ? ? ? ? ? ? ? url = window.URL.createObjectURL(file);

? ? ? ? ? ? } else if (window.webkitURL != undefined) {

? ? ? ? ? ? ? ? url = window.webkitURL.createObjectURL(file);

? ? ? ? ? ? }

? ? ? ? ? ? return url;

? ? //}

? ? ? ? </script>

? ? </body>


? ? </html>

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • (純js的質量壓縮,非長寬壓縮) 此demo為大于1M對圖片進行壓縮上傳 若小于1M則原圖上傳,可以根據自己實際需...
    丨ChenSir丨閱讀 981評論 0 1
  • 前端無法像原生APP一樣直接操作本地文件,否則的話打開個網頁就能把用戶電腦上的文件偷光了,所以需要通過用戶觸發,用...
    雷波_viho閱讀 832評論 0 1
  • 單例模式 適用場景:可能會在場景中使用到對象,但只有一個實例,加載時并不主動創建,需要時才創建 最常見的單例模式,...
    Obeing閱讀 2,093評論 1 10
  • mean to add the formatted="false" attribute?.[ 46% 47325/...
    ProZoom閱讀 2,719評論 0 3
  • 用手藝穿透知識,日課的習慣,就是肆意訓練的累積。 比如投資,看似簡單,日復一日的看有標準要求的財報,但久而重復,把...
    撿石頭的村童閱讀 138評論 0 0