各種返回圖片在前端顯示以及轉(zhuǎn)化

前言


作為前端工程師 的我們,日常少不了會(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í)候,返回的卻是


image.png

出現(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)化

image.png

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ì)比較好。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末十办,一起剝皮案震驚了整個(gè)濱河市秀撇,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌向族,老刑警劉巖呵燕,帶你破解...
    沈念sama閱讀 212,542評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異件相,居然都是意外死亡虏等,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,596評論 3 385
  • 文/潘曉璐 我一進(jìn)店門适肠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人候引,你說我怎么就攤上這事侯养。” “怎么了澄干?”我有些...
    開封第一講書人閱讀 158,021評論 0 348
  • 文/不壞的土叔 我叫張陵逛揩,是天一觀的道長。 經(jīng)常有香客問我麸俘,道長辩稽,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,682評論 1 284
  • 正文 為了忘掉前任从媚,我火速辦了婚禮逞泄,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘拜效。我一直安慰自己喷众,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,792評論 6 386
  • 文/花漫 我一把揭開白布紧憾。 她就那樣靜靜地躺著到千,像睡著了一般。 火紅的嫁衣襯著肌膚如雪大磺。 梳的紋絲不亂的頭發(fā)上锣险,一...
    開封第一講書人閱讀 49,985評論 1 291
  • 那天,我揣著相機(jī)與錄音我纪,去河邊找鬼了赵。 笑死潜支,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的斟览。 我是一名探鬼主播毁腿,決...
    沈念sama閱讀 39,107評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼苛茂!你這毒婦竟也來了已烤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,845評論 0 268
  • 序言:老撾萬榮一對情侶失蹤妓羊,失蹤者是張志新(化名)和其女友劉穎胯究,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體躁绸,經(jīng)...
    沈念sama閱讀 44,299評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡裕循,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,612評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了净刮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片剥哑。...
    茶點(diǎn)故事閱讀 38,747評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖淹父,靈堂內(nèi)的尸體忽然破棺而出株婴,到底是詐尸還是另有隱情,我是刑警寧澤暑认,帶...
    沈念sama閱讀 34,441評論 4 333
  • 正文 年R本政府宣布困介,位于F島的核電站,受9級特大地震影響蘸际,放射性物質(zhì)發(fā)生泄漏座哩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,072評論 3 317
  • 文/蒙蒙 一粮彤、第九天 我趴在偏房一處隱蔽的房頂上張望根穷。 院中可真熱鬧,春花似錦导坟、人聲如沸缠诅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,828評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽管引。三九已至,卻和暖如春闯两,著一層夾襖步出監(jiān)牢的瞬間褥伴,已是汗流浹背谅将。 一陣腳步聲響...
    開封第一講書人閱讀 32,069評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留重慢,地道東北人饥臂。 一個(gè)月前我還...
    沈念sama閱讀 46,545評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像似踱,于是被迫代替她去往敵國和親隅熙。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,658評論 2 350

推薦閱讀更多精彩內(nèi)容