前言
作為前端工程師 的我們,日常少不了會(huì)跟圖片打交道。
以下是我了解的败砂。
一辨嗽、圖片在后端中存儲(chǔ)
一般來說世落,圖片在后端的存儲(chǔ)方式分為兩種:
其一:可以將圖片以獨(dú)立文件的形式存儲(chǔ)在服務(wù)器的指定文件夾中,再將路徑存入數(shù)據(jù)庫字段中;
其二:將圖片轉(zhuǎn)換成二進(jìn)制流糟需,直接存儲(chǔ)到數(shù)據(jù)庫的 Image 類型字段中.
對于第一種存儲(chǔ)方式屉佳,我們前端直接將存儲(chǔ)路徑賦值給 src 屬性即可輕松顯示。
對于第二種存儲(chǔ)方式洲押,我們前端需要將其二進(jìn)制流交由 blob 對象處理武花,然后通過 blob 的 API 生成臨時(shí) URL 賦值給 src 屬性來顯示。
二诅诱、在 chrome 的 network 查看的時(shí)候髓堪,返回的也是這個(gè)圖片(二進(jìn)制)
可是,在 打印的時(shí)候,返回的卻是
出現(xiàn)問題的原因的axios 默認(rèn)返回的是 json 文本形式干旁,二進(jìn)制圖片數(shù)據(jù)被強(qiáng)制轉(zhuǎn)換成了 json 文本形式驶沼。
找到了原因,解決方案就好辦了争群。我們在 axios 里面回怜,responseType 默認(rèn)返回?cái)?shù)據(jù)類型是 json,將其改為返回?cái)?shù)據(jù)類型 blob换薄。
export function miniprogramQrcode (params) {
return axios.post(
env.MI_URL + '/XXXX/XXX/XXXX',
params,
// 將responseType的默認(rèn)json改為blob
{
responseType: 'blob',
emulateJSON: true
}).then(res => {
if (res.data) {
return Promise.resolve(res.data)
} else {
throw res
}
}).catch(err => {
return Promise.reject(err)
})
}
接下來的問題是玉雾,如何處理blob對象,將其顯示在前端頁面呢轻要?
代碼如下
createMiniQrcode (blob) {
let img = document.createElement('img')
img.onload = function (e) {
// 元素的onload 事件觸發(fā)后將銷毀URL對象, 釋放內(nèi)存复旬。
window.URL.revokeObjectURL(img.src)
}
// 瀏覽器允許使用URL.createObjectURL()方法,針對 Blob 對象生成一個(gè)臨時(shí) URL冲泥。
// 這個(gè) URL 以blob://開頭,表明對應(yīng)一個(gè) Blob 對象驹碍。
img.src = window.URL.createObjectURL(blob)
document.querySelector('.imgQrCode').appendChild(img)
}
三、url凡恍、base64志秃、blob,三者之間轉(zhuǎn)化
1. url 轉(zhuǎn) base64
// 原理: 利用canvas.toDataURL的API轉(zhuǎn)化成base64
urlToBase64(url) {
return new Promise ((resolve,reject) => {
let image = new Image();
image.onload = function() {
let canvas = document.createElement('canvas');
canvas.width = this.naturalWidth;
canvas.height = this.naturalHeight;
// 將圖片插入畫布并開始繪制
canvas.getContext('2d').drawImage(image, 0, 0);
// result
let result = canvas.toDataURL('image/png')
resolve(result);
};
// CORS 策略嚼酝,會(huì)存在跨域問題https://stackoverflow.com/questions/20424279/canvas-todataurl-securityerror
image.setAttribute("crossOrigin",'Anonymous');
image.src = url;
// 圖片加載失敗的錯(cuò)誤處理
image.onerror = () => {
reject(new Error('圖片流異常'));
};
}
你可以這樣調(diào)用:
let imgUrL = `http://XXX.jpg`
this.getDataUri(imgUrL).then(res => {
// 轉(zhuǎn)化后的base64圖片地址
console.log('base64', res)
})
2. base64 轉(zhuǎn) blob
// 原理:利用URL.createObjectURL為blob對象創(chuàng)建臨時(shí)的URL
base64ToBlob ({b64data = '', contentType = '', sliceSize = 512} = {}) {
return new Promise((resolve, reject) => {
// 使用 atob() 方法將數(shù)據(jù)解碼
let byteCharacters = atob(b64data);
let byteArrays = [];
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
let slice = byteCharacters.slice(offset, offset + sliceSize);
let byteNumbers = [];
for (let i = 0; i < slice.length; i++) {
byteNumbers.push(slice.charCodeAt(i));
}
// 8 位無符號整數(shù)值的類型化數(shù)組浮还。內(nèi)容將初始化為 0。
// 如果無法分配請求數(shù)目的字節(jié)闽巩,則將引發(fā)異常钧舌。
byteArrays.push(new Uint8Array(byteNumbers));
}
let result = new Blob(byteArrays, {
type: contentType
})
result = Object.assign(result,{
// jartto: 這里一定要處理一下 URL.createObjectURL
preview: URL.createObjectURL(result),
name: `圖片示例.png`
});
resolve(result)
})
}
你可以這樣調(diào)用:
let base64 = base64.split(',')[1]
this.base64ToBlob({b64data: base64, contentType: 'image/png'}).then(res => {
// 轉(zhuǎn)后后的blob對象
console.log('blob', res)
})
3.blob 轉(zhuǎn) base64
// 原理:利用fileReader的readAsDataURL,將blob轉(zhuǎn)為base64
blobToBase64(blob) {
return new Promise((resolve, reject) => {
const fileReader = new FileReader();
fileReader.onload = (e) => {
resolve(e.target.result);
};
// readAsDataURL
fileReader.readAsDataURL(blob);
fileReader.onerror = () => {
reject(new Error('文件流異常'));
};
});
}
你可以這樣調(diào)用:
this.blobToBase64(blob).then(res => {
// 轉(zhuǎn)化后的base64
console.log('base64', res)
})
四又官、三種顯示方式延刘,哪種更優(yōu)雅呢?
url: 一般來說六敬,圖片的顯示還是建議使用url的方式比較好碘赖。如果后端傳過來的字段是圖片路徑的話。
base64:如果圖片較大外构,圖片的色彩層次比較豐富普泡,則不適合使用這種方式,因?yàn)槠銪ase64編碼后的字符串非常大审编,會(huì)明顯增大HTML頁面撼班,影響加載速度。 如果圖片像loading或者表格線這樣的垒酬,大小極小砰嘁,但又占據(jù)了一次HTTP請求件炉,而很多地方都會(huì)使用。則非常適用“base64:URL圖片”技術(shù)進(jìn)行優(yōu)化了矮湘!斟冕。
blob: 當(dāng)后端返回特定的圖片二進(jìn)制流的時(shí)候,就像我第一part里的情景再現(xiàn)說的缅阳,前端用blob容器接收磕蛇。圖片用blob展示會(huì)比較好。