最近做了在小程序嵌入的H5頁(yè)面的選擇并上傳圖片的功能座每,過(guò)程中踩了很多坑前鹅,寫(xiě)下此文記錄一下。
首先峭梳,查看小程序文檔可知舰绘,web-view有以下幾個(gè)圖片API:
但是!4型帧捂寿!使用這些API首先要配置微信簽名:
wx.config({
debug: false, // 開(kāi)啟調(diào)試模式,調(diào)用的所有api的返回值會(huì)在客戶端alert出來(lái)
appId: datad.appid, // 必填,公眾號(hào)的唯一標(biāo)識(shí)
timestamp: datad.timestamp, // 必填孵运,生成簽名的時(shí)間戳
nonceStr: datad.noncestr, // 必填秦陋,生成簽名的隨機(jī)串
signature: datad.signature,// 必填,簽名治笨,見(jiàn)附錄1
jsApiList: [
"openLocation"
] // 必填驳概,需要使用的JS接口列表,所有JS接口列表見(jiàn)附錄2
});
配置好微信簽名后旷赖,調(diào)用wx.ready()接口顺又,把需要使用的wx.chooseImage()作為參數(shù);
wx.ready(function() {
wx.chooseImage({
count: 1, // 默認(rèn)9
sizeType: ["original", "compressed"], // 可以指定是原圖還是壓縮圖等孵,默認(rèn)二者都有
sourceType: ["album", "camera"],// 可以指定來(lái)源是相冊(cè)還是相機(jī)稚照,默認(rèn)二者都有
success: function(res) {
// console.log(res.localIds);
},
fail: function(res) {
//
}
});
});
調(diào)用wx.chooseImage() 可以打開(kāi)相冊(cè)或相機(jī)選擇圖片,返回圖片的localId,localId可以作為img 標(biāo)簽的src直接顯示果录。
選擇好圖片并在界面上成功顯示后腌闯,下一步就是上傳了。
通過(guò)微信的wx.chooseImage接口獲取的圖片localId是以weixin://開(kāi)頭的雕憔,不能直接上傳到我們自己的服務(wù)器姿骏。
一個(gè)辦法是使用wx.uploadImage,wx.uploadImage接口是上傳到微信的服務(wù)器斤彼,后端需要再通過(guò)接口下載圖片到自己的服務(wù)器分瘦,上傳圖片有效期只有3天。
wx.uploadImage({
localId: '', // 需要上傳的圖片的本地ID琉苇,由chooseImage接口獲得
isShowProgressTips: 1, // 默認(rèn)為1嘲玫,顯示進(jìn)度提示
success: function (res) {
var serverId = res.serverId; // 返回圖片的服務(wù)器端ID
}
});
這個(gè)方法可行,但很不方便并扇。
另一個(gè)辦法就是通過(guò)把圖片轉(zhuǎn)換成base64去团,再轉(zhuǎn)換成file,這樣就能上傳到自己的服務(wù)器了穷蛹。
我采用的是后一種辦法土陪。
通過(guò)wx.getLocalImgData接口,可以獲取到圖片的base64數(shù)據(jù)肴熏。
這里有兩個(gè)坑鬼雀,在android系統(tǒng)調(diào)用這個(gè)接口,返回的res.localData就是base64數(shù)據(jù)蛙吏,而在ios系統(tǒng)源哩,返回的res.localData有一段前綴data:image/jgp;base64, ,需要去除鸦做。
convertLocalIdToBase64(id) {
return new Promise((resolve, reject) => {
wx.getLocalImgData({
localId: id,
success: res => {
if (window.navigator.userAgent.match(/iPhone|ipad|ipod|ios/i)) {
let base64 = res.localData.replace("data:image/jgp;base64,", "");
resolve(base64);
} else {
resolve(res.localData);
}
}
});
});
},
接下來(lái)就是把base64數(shù)據(jù)轉(zhuǎn)換成file:
convertBase64UrlToFile(urlData) {
return new Promise((resolve, reject) => {
var bytes = atob(urlData);
var ab = bytes.length;
var ia = new Uint8Array(ab);
for (var i = 0; i < ab; i++) {
ia[i] = bytes.charCodeAt(i);
}
let file = new File([ia], "123.png", { type: "image/png" });
resolve(file);
});
},
這里也有一個(gè)坑励烦,這段代碼在ios9.3的系統(tǒng)中報(bào)錯(cuò)了。
經(jīng)排查泼诱,原因是部分手機(jī)系統(tǒng)版本還不支持File坛掠,ios低于9.3(含)
、安卓低于4.4(含)
都不支持坷檩,見(jiàn):caniuse
解決辦法就是:將Base64轉(zhuǎn)換為Blob對(duì)象却音,blob的兼容性相對(duì)File會(huì)更好一些。這一點(diǎn)參考文章
這里我嘗試把base64轉(zhuǎn)換成blob對(duì)象矢炼,但是上傳圖片時(shí)還是失敗了系瓢,應(yīng)該是后端不支持blob。這里如果實(shí)在要用blob句灌,后端估計(jì)也要修改接口夷陋。
我們項(xiàng)目的后端嫌麻煩欠拾,所以我們最終決定,不兼容低版本的系統(tǒng)了骗绕。藐窄。。所以我還是用File來(lái)上傳酬土。
uploadFile(file) {
return new Promise((resolve, reject) => {
var formDataToUpload = new FormData();
formDataToUpload.append("file", file);
let url = ‘’;
axios({
method: "post",
url,
data: formDataToUpload,
dataType: "file",
processData: false,
contentType: "multipart/form-data"
})
.then(data => {
resolve(data.result);
})
.catch(err => {
reject(err);
});
});
},
上傳成功荆忍!