如果不考慮ie9兼容性,實現【上傳圖片】大致的思路如下:
- 由于公司是將所有上傳的圖片都放到【代理服務器】里。所以【上傳圖片】其實是上傳到【代理服務器】。可以通過ajax,通過FormData將圖片上傳到【代理服務器】。
- 從【代理服務器】拿到的回調里,有壓縮過的圖片的url,將這個url賦值給DOM里圖片img的src就行了。由于我們的項目是用的vue,直接綁定:src就行了。
- 上傳圖片到【代理服務器】完成后,需要將url等相關數據(我們的項目后端需要一個pid,來實現用戶下次訪問時,后端從代理服務器根據這個pid來獲取相應圖片】),通過ajax發給后端(我們公司的服務器)。
思路很簡單,而且核心關鍵其實就是第1點,第2,3只是簡單的DOM操作和ajax交換數據。接下來就只關注第1點的具體實現。
1. 通過formData,結合html5的input type=file來實現上傳
<input name="file" type="file" @change="update" accept="image/x-png, image/jpg, image/jpeg">
對應的,Vue的methods里,update方法如下:
update(e) {
let file = e.target.files[0]; //input提供的API,如果需要過濾圖片尺寸,也可以在e.target.files[0]里拿到相應數據。
let param = new FormData(); //通過FormData來將圖片信息發送給服務器;FormData是html5的私有對象。
param.append('file', file, file.name);
/* 接下來,就是通過ajax,發送form數據到服務器,我們公司用的jQuery,比較普遍的應該是axios吧 */
$.ajax({
url: '/image/upload',
type: 'POST',
data: param, //保證data格式為FormData
processData: false, //必須false才會自動加上正確的Content-Type
contentType: false //必須false才會避開jQuery對 formdata 的默認處理
}).done(function(res) {
// 回調
})
}
然后,在回調里,給DOM里的圖片src賦值就行了。
當然,如果不兼容ie9,現在這個方案就行了。
在ie9下,不支持FormData。所以在ie9下,只能通過form表單形式實現圖片上傳。
2. ie9下通過form表單實現圖片上傳
<form id="myForm" method="post" action="/image/ieupload" enctype="multipart/form-data">
<input name="file" type="file" @change="update" accept="image/x-png, image/jpg, image/jpeg">
<input id="submit" type="submit" style="display:none">
</form>
form里,enctype必須為mulitpart/form-data,表單中enctype="multipart/form-data"的意思,是設置表單的MIME編碼。默認情況,這個編碼格式是application/x-www-form-urlencoded,不能用于文件上傳;只有使用了multipart/form- data,才能完整的傳遞文件數據。
同時要加上input type="submit",只有點擊(或者trigger click)這個按鈕,才會將數據發送到服務器。
這樣,在上面的update方法里,就需要加一層判斷,如果不是ie9(或者是瀏覽器不支持formData),就通過formData結合ajax實現上傳圖片。通過formData的好處是不用在DOM里寫form,(form表單提交,一般的服務器處理方式是重定向),只通過ajax跟后端服務器交換數據可以讓接口更加統一。而如果是ie9,則必須要通過form表單提交,在update方法里,通過trigger #submit元素的click事件來完成表單提交。
但是,如果服務器返回的是json,并不能拿到服務器返回的數據,而是直接提示下載或打開:
之所以ie9下提示打開或者保持,是因為:
ie無法解析回調里的json數據,就是說如果服務器返回json數據,ie會把它當做文件來處理,顯示打開或保存。
解決方法如下:
在后端返回的時候自定義contype-type為"text/html",比如在node中這樣寫res.setHeader('Content-Type', 'text/html')。
參考資料:文件上傳返回JSON數據,在IE下提示下載文件
這樣改完之后,會發現,雖然現在不提示下載文件了,可是會直接跳轉到新頁面。
在ajax未誕生前,都是用iframe來實現無刷新的效果。為了避免跳轉到新頁面,需要手動指定跳轉的頁面為一個iframe。然后取到iframe里的回調內容后,將相應內容從iframe里取出來使用。
另外,由于因為file是Readonly,如果用戶上傳的圖片不符合要求,想清空value,只能用新的file替換之前的file。
參考資料:http://www.cnblogs.com/nsky/archive/2012/12/28/2836578.html
3. 拓展:本地預覽(fileReader)
fileReader就是html5為我們提供的讀取文件的api。它的作用就是把文本流按指定格式讀取到緩存,以供js調用。
參考資料:上傳圖片本地預覽
通過fileReader的readAsDataURL方法,將文件讀取為 DataURL,然后賦值給img的src,就大功告成啦。
DataURL有其固定的格式,如下:
data:[文件格式];base64,[文本流base64編碼]。