如果不考慮ie9兼容性,實(shí)現(xiàn)【上傳圖片】大致的思路如下:
- 由于公司是將所有上傳的圖片都放到【代理服務(wù)器】里。所以【上傳圖片】其實(shí)是上傳到【代理服務(wù)器】??梢酝ㄟ^ajax,通過FormData將圖片上傳到【代理服務(wù)器】。
- 從【代理服務(wù)器】拿到的回調(diào)里,有壓縮過的圖片的url,將這個(gè)url賦值給DOM里圖片img的src就行了。由于我們的項(xiàng)目是用的vue,直接綁定:src就行了。
- 上傳圖片到【代理服務(wù)器】完成后,需要將url等相關(guān)數(shù)據(jù)(我們的項(xiàng)目后端需要一個(gè)pid,來實(shí)現(xiàn)用戶下次訪問時(shí),后端從代理服務(wù)器根據(jù)這個(gè)pid來獲取相應(yīng)圖片】),通過ajax發(fā)給后端(我們公司的服務(wù)器)。
思路很簡單,而且核心關(guān)鍵其實(shí)就是第1點(diǎn),第2,3只是簡單的DOM操作和ajax交換數(shù)據(jù)。接下來就只關(guān)注第1點(diǎn)的具體實(shí)現(xiàn)。
1. 通過formData,結(jié)合html5的input type=file來實(shí)現(xiàn)上傳
<input name="file" type="file" @change="update" accept="image/x-png, image/jpg, image/jpeg">
對(duì)應(yīng)的,Vue的methods里,update方法如下:
update(e) {
let file = e.target.files[0]; //input提供的API,如果需要過濾圖片尺寸,也可以在e.target.files[0]里拿到相應(yīng)數(shù)據(jù)。
let param = new FormData(); //通過FormData來將圖片信息發(fā)送給服務(wù)器;FormData是html5的私有對(duì)象。
param.append('file', file, file.name);
/* 接下來,就是通過ajax,發(fā)送form數(shù)據(jù)到服務(wù)器,我們公司用的jQuery,比較普遍的應(yīng)該是axios吧 */
$.ajax({
url: '/image/upload',
type: 'POST',
data: param, //保證data格式為FormData
processData: false, //必須false才會(huì)自動(dòng)加上正確的Content-Type
contentType: false //必須false才會(huì)避開jQuery對(duì) formdata 的默認(rèn)處理
}).done(function(res) {
// 回調(diào)
})
}
然后,在回調(diào)里,給DOM里的圖片src賦值就行了。
當(dāng)然,如果不兼容ie9,現(xiàn)在這個(gè)方案就行了。
在ie9下,不支持FormData。所以在ie9下,只能通過form表單形式實(shí)現(xiàn)圖片上傳。
2. ie9下通過form表單實(shí)現(xiàn)圖片上傳
<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"的意思,是設(shè)置表單的MIME編碼。默認(rèn)情況,這個(gè)編碼格式是application/x-www-form-urlencoded,不能用于文件上傳;只有使用了multipart/form- data,才能完整的傳遞文件數(shù)據(jù)。
同時(shí)要加上input type="submit",只有點(diǎn)擊(或者trigger click)這個(gè)按鈕,才會(huì)將數(shù)據(jù)發(fā)送到服務(wù)器。
這樣,在上面的update方法里,就需要加一層判斷,如果不是ie9(或者是瀏覽器不支持formData),就通過formData結(jié)合ajax實(shí)現(xiàn)上傳圖片。通過formData的好處是不用在DOM里寫form,(form表單提交,一般的服務(wù)器處理方式是重定向),只通過ajax跟后端服務(wù)器交換數(shù)據(jù)可以讓接口更加統(tǒng)一。而如果是ie9,則必須要通過form表單提交,在update方法里,通過trigger #submit元素的click事件來完成表單提交。
但是,如果服務(wù)器返回的是json,并不能拿到服務(wù)器返回的數(shù)據(jù),而是直接提示下載或打開:

之所以ie9下提示打開或者保持,是因?yàn)椋?br> ie無法解析回調(diào)里的json數(shù)據(jù),就是說如果服務(wù)器返回json數(shù)據(jù),ie會(huì)把它當(dāng)做文件來處理,顯示打開或保存。
解決方法如下:
在后端返回的時(shí)候自定義contype-type為"text/html",比如在node中這樣寫res.setHeader('Content-Type', 'text/html')。
參考資料:文件上傳返回JSON數(shù)據(jù),在IE下提示下載文件
這樣改完之后,會(huì)發(fā)現(xiàn),雖然現(xiàn)在不提示下載文件了,可是會(huì)直接跳轉(zhuǎn)到新頁面。

在ajax未誕生前,都是用iframe來實(shí)現(xiàn)無刷新的效果。為了避免跳轉(zhuǎn)到新頁面,需要手動(dòng)指定跳轉(zhuǎn)的頁面為一個(gè)iframe。然后取到iframe里的回調(diào)內(nèi)容后,將相應(yīng)內(nèi)容從iframe里取出來使用。
參考資料:通過iframe防止form表單提交時(shí)跳轉(zhuǎn)頁面
另外,由于因?yàn)閒ile是Readonly,如果用戶上傳的圖片不符合要求,想清空value,只能用新的file替換之前的file。
參考資料:http://www.cnblogs.com/nsky/archive/2012/12/28/2836578.html
3. 拓展:本地預(yù)覽(fileReader)
fileReader就是html5為我們提供的讀取文件的api。它的作用就是把文本流按指定格式讀取到緩存,以供js調(diào)用。
參考資料:上傳圖片本地預(yù)覽
通過fileReader的readAsDataURL方法,將文件讀取為 DataURL,然后賦值給img的src,就大功告成啦。
DataURL有其固定的格式,如下:
data:[文件格式];base64,[文本流base64編碼]。
