js如何實(shí)現(xiàn)小程序wx.arrayBufferToBase64方法實(shí)例
前言
在小程序開(kāi)發(fā)中,需要將接口請(qǐng)求獲得的arrayBuffer數(shù)據(jù),轉(zhuǎn)換為base64格式數(shù)據(jù),進(jìn)行圖片的顯示。
微信小程序提供了wx.arrayBufferToBase64方法,但很不幸,這個(gè)方法在基礎(chǔ)庫(kù)版本 2.4.0 起已廢棄,已不推薦使用。
雖然目前即使小程序基礎(chǔ)庫(kù)版本為2.22.0,也能正常使用。但是不確定未來(lái)哪天,在更新的基礎(chǔ)庫(kù)中,該方法被刪除。這樣就會(huì)帶來(lái)項(xiàng)目上的隱患。
所以需要自己去實(shí)現(xiàn)arrayBuffer轉(zhuǎn)為base64這一過(guò)程。
探索失敗的過(guò)程
- new FileReader()在小程序中無(wú)法進(jìn)行使用。無(wú)法使用new FileReader()實(shí)例中的readAsDataURL方法將數(shù)據(jù)轉(zhuǎn)為base64。如果不熟悉該方法,可以查看FileReader介紹
- URL.createObjectURL在小程序中無(wú)法使用。無(wú)法使用該方法將數(shù)據(jù)轉(zhuǎn)為在內(nèi)存中的地址,進(jìn)而能被image標(biāo)簽進(jìn)行引用。如果不熟悉該方法,可以查看URL.createObjectURL講解
- window.btoa在小程序中無(wú)法使用。無(wú)法將文本直接轉(zhuǎn)為base64格式。
好了,條條大路都被阻斷了。那就該自己鋪路搭橋了。
卡殼的arrayBuffer轉(zhuǎn)base64
問(wèn)題的起始條件有arrayBuffer數(shù)據(jù),期望結(jié)果是最終形成base64格式數(shù)據(jù)。那開(kāi)始進(jìn)行求解。
首先我們得來(lái)說(shuō)說(shuō)arrayBuffer這回事。
在JavaScript中,有一個(gè)很常用的引用數(shù)據(jù)類(lèi)型Array,你可以在里面放字符串、數(shù)字、對(duì)象、布爾值等等等等。它存放在堆中,可以自由增減。
ArrayBuffer 對(duì)象用來(lái)表示通用的、固定長(zhǎng)度的原始二進(jìn)制數(shù)據(jù)緩沖區(qū)。它是一個(gè)字節(jié)數(shù)組,通常在其他語(yǔ)言中稱(chēng)為“byte array”。它的誕生就是為了解決一個(gè)問(wèn)題:操作二進(jìn)制數(shù)據(jù)。
只由0和1組成的二進(jìn)制數(shù)據(jù)往往是非常巨大的,上千個(gè)字節(jié)可以說(shuō)司空見(jiàn)慣,傳統(tǒng)的Array這時(shí)候處理起二進(jìn)制數(shù)據(jù)起來(lái)就顯得非常低效,所以ArrayBuffer出現(xiàn)了,它作為一塊專(zhuān)用的內(nèi)存區(qū)域存放在棧中,取數(shù)據(jù)非???。
我們現(xiàn)在通過(guò)new ArrayBuffer(10)初始化一個(gè)buffer實(shí)例,看看會(huì)得到什么。
let buffer = new ArrayBuffer(10); console.log(buffer); // 在控制臺(tái)上顯示如下 ArrayBuffer(10) byteLength: 10 [[Prototype]]: ArrayBuffer [[Int8Array]]: Int8Array(10) [[Uint8Array]]: Uint8Array(10) [[Int16Array]]: Int16Array(5) [[ArrayBufferByteLength]]: 10 [[ArrayBufferData]]: 1367
可以看到在ArrayBuffer中,主要存放了幾個(gè)“視圖”,Int8Array表示8位有符號(hào)整數(shù)數(shù)組,Int16Array表示16位有符號(hào)整數(shù)數(shù)組,Uint8Array則表示8位無(wú)符號(hào)整數(shù)數(shù)組。
當(dāng)然,如果比如說(shuō)我們想取出Int8Array這個(gè)數(shù)組來(lái),是不能直接通過(guò)buffer.Int8Array來(lái)取的。這是因?yàn)锳rrayBuffer不能直接通過(guò)下標(biāo)去讀寫(xiě),我們需要把它轉(zhuǎn)成一個(gè)類(lèi)型化數(shù)組(TypedArray)。
你不能直接操作 ArrayBuffer 的內(nèi)容,而是要通過(guò)類(lèi)型數(shù)組對(duì)象或 DataView 對(duì)象來(lái)操作,它們會(huì)將緩沖區(qū)中的數(shù)據(jù)表示為特定的格式,并通過(guò)這些格式來(lái)讀寫(xiě)緩沖區(qū)的內(nèi)容。
const myTypedArray = new Uint8Array(buffer)
轉(zhuǎn)化完之后,我們我們不僅可以通過(guò)下標(biāo)去對(duì)類(lèi)型化數(shù)組進(jìn)行索引,也可以獲取其length,當(dāng)然TypedArray仍與普通的Array存在細(xì)微的區(qū)別,那就是假設(shè)我們用超出邊界的索引語(yǔ)法去獲取數(shù)組元素時(shí),TypedArray并不會(huì)去原型鏈中進(jìn)行查找。
現(xiàn)在我們已經(jīng)拿到了這個(gè)類(lèi)型化數(shù)組,是時(shí)候把它轉(zhuǎn)成普通字符串了??纯碨tring.fromCharCode這個(gè)函數(shù),它接受的參數(shù)為一堆代碼單元序列,輸出一個(gè)普通字符串。而我們剛剛得到的類(lèi)型化數(shù)組,里面存放的正是代碼單元。
const str = String.fromCharCode(...myTypedArray)
這里我們用拓展運(yùn)算符...把類(lèi)型數(shù)組的代碼單元解出來(lái),一次性轉(zhuǎn)完,得到一個(gè)普通的字符串。
最后,我們需要借助一個(gè)window對(duì)象的方法,也就是btoa方法,它的作用是:把一個(gè)普通字符串編碼成base-64格式的字符串。
上面看似很好,但是在最后一步,btoa,在小程序中是沒(méi)有該方法的去使用的。需要自己去實(shí)現(xiàn)btoa這個(gè)方法。
關(guān)鍵點(diǎn)btoa的實(shí)現(xiàn)
因?yàn)樵摵瘮?shù),在瀏覽器中已經(jīng)實(shí)現(xiàn),所以更多使用在小程序及node環(huán)境中。所以總體以module.exports進(jìn)行方法的輸出,以require形式進(jìn)行引入。
輸出方法
module.exports = { btoa: ..., atob: ... }
引入文件
const { btoa } = require('./base64')
base64.js
var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", a256 = '', r64 = [256], r256 = [256], i = 0; var UTF8 = { /** * Encode multi-byte Unicode string into utf-8 multiple single-byte characters * (BMP / basic multilingual plane only) * * Chars in range U+0080 - U+07FF are encoded in 2 chars, U+0800 - U+FFFF in 3 chars * * @param {String} strUni Unicode string to be encoded as UTF-8 * @returns {String} encoded string */ encode: function (strUni) { // use regular expressions & String.replace callback function for better efficiency // than procedural approaches var strUtf = strUni.replace(/[\u0080-\u07ff]/g, // U+0080 - U+07FF => 2 bytes 110yyyyy, 10zzzzzz function (c) { var cc = c.charCodeAt(0); return String.fromCharCode(0xc0 | cc >> 6, 0x80 | cc & 0x3f); }) .replace(/[\u0800-\uffff]/g, // U+0800 - U+FFFF => 3 bytes 1110xxxx, 10yyyyyy, 10zzzzzz function (c) { var cc = c.charCodeAt(0); return String.fromCharCode(0xe0 | cc >> 12, 0x80 | cc >> 6 & 0x3F, 0x80 | cc & 0x3f); }); return strUtf; }, /** * Decode utf-8 encoded string back into multi-byte Unicode characters * * @param {String} strUtf UTF-8 string to be decoded back to Unicode * @returns {String} decoded string */ decode: function (strUtf) { // note: decode 3-byte chars first as decoded 2-byte strings could appear to be 3-byte char! var strUni = strUtf.replace(/[\u00e0-\u00ef][\u0080-\u00bf][\u0080-\u00bf]/g, // 3-byte chars function (c) { // (note parentheses for precence) var cc = ((c.charCodeAt(0) & 0x0f) << 12) | ((c.charCodeAt(1) & 0x3f) << 6) | (c.charCodeAt(2) & 0x3f); return String.fromCharCode(cc); }) .replace(/[\u00c0-\u00df][\u0080-\u00bf]/g, // 2-byte chars function (c) { // (note parentheses for precence) var cc = (c.charCodeAt(0) & 0x1f) << 6 | c.charCodeAt(1) & 0x3f; return String.fromCharCode(cc); }); return strUni; } }; while (i < 256) { var c = String.fromCharCode(i); a256 += c; r256[i] = i; r64[i] = b64.indexOf(c); ++i; } function code(s, discard, alpha, beta, w1, w2) { s = String(s); var buffer = 0, i = 0, length = s.length, result = '', bitsInBuffer = 0; while (i < length) { var c = s.charCodeAt(i); c = c < 256 ? alpha[c] : -1; buffer = (buffer << w1) + c; bitsInBuffer += w1; while (bitsInBuffer >= w2) { bitsInBuffer -= w2; var tmp = buffer >> bitsInBuffer; result += beta.charAt(tmp); buffer ^= tmp << bitsInBuffer; } ++i; } if (!discard && bitsInBuffer > 0) result += beta.charAt(buffer << (w2 - bitsInBuffer)); return result; } var Plugin = function (dir, input, encode) { return input ? Plugin[dir](input, encode) : dir ? null : this; }; Plugin.btoa = Plugin.encode = function (plain, utf8encode) { plain = Plugin.raw === false || Plugin.utf8encode || utf8encode ? UTF8.encode(plain) : plain; plain = code(plain, false, r256, b64, 8, 6); return plain + '===='.slice((plain.length % 4) || 4); }; Plugin.atob = Plugin.decode = function (coded, utf8decode) { coded = coded.replace(/[^A-Za-z0-9\+\/\=]/g, ""); coded = String(coded).split('='); var i = coded.length; do { --i; coded[i] = code(coded[i], true, r64, a256, 6, 8); } while (i > 0); coded = coded.join(''); return Plugin.raw === false || Plugin.utf8decode || utf8decode ? UTF8.decode(coded) : coded; }; module.exports = { btoa: Plugin.btoa, atob: Plugin.atob }
修成正果
有時(shí)候后臺(tái)把圖片資源通過(guò)arrayBuffer傳給前端,這時(shí)候?yàn)榱四苷o@示,我們還需要在轉(zhuǎn)化的base64字符串前面拼接上data:image/jpeg;base64,
所以我們整理一下,可以得出這樣一個(gè)函數(shù):
const { btoa } = require('./base64') const arrayBufferToBase64Img = (buffer) => { const str = String.fromCharCode(...new Uint8Array(buffer)); return `data:image/jpeg;base64,${btoa(str)}`; }
整個(gè)流程如下:
得到一個(gè)ArrayBuffer ---> 轉(zhuǎn)成類(lèi)型化數(shù)組以正常讀取(Uint8Array) --> 轉(zhuǎn)成普通字符串(String.fromCharCode) --> 轉(zhuǎn)成base64字符串(btoa)
總結(jié)
到此這篇關(guān)于js如何實(shí)現(xiàn)小程序wx.arrayBufferToBase64方法實(shí)例的文章就介紹到這了,更多相關(guān)js實(shí)現(xiàn)小程序wx.arrayBufferToBase64內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
webpack中CommonsChunkPlugin詳細(xì)教程(小結(jié))
本篇文章主要介紹了webpack中CommonsChunkPlugin詳細(xì)教程(小結(jié)),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-11-11JavaScript實(shí)現(xiàn)簡(jiǎn)單生成隨機(jī)顏色的方法
這篇文章主要介紹了JavaScript實(shí)現(xiàn)簡(jiǎn)單生成隨機(jī)顏色的方法,涉及javascript隨機(jī)數(shù)與字符串運(yùn)算及頁(yè)面元素屬性動(dòng)態(tài)操作相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-09-09原生JavaScript實(shí)現(xiàn)AJAX、JSONP
本篇文章將會(huì)講解原生JavaScript如何實(shí)現(xiàn)簡(jiǎn)單的AJAX,還有跨域請(qǐng)求JSONP。具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧2017-02-02JavaScript設(shè)計(jì)模式之單例模式原理與用法實(shí)例分析
這篇文章主要介紹了JavaScript設(shè)計(jì)模式之單例模式原理與用法,結(jié)合實(shí)例形式分析了單例模式的原理、命名空間的使用、閉包、惰性單例形式以及單例模式的基本應(yīng)用,需要的朋友可以參考下2018-07-07JavaScript錯(cuò)誤處理之分析 Uncaught(in promise) error的
在開(kāi)發(fā)過(guò)程中,JavaScript的錯(cuò)誤處理是一個(gè)老生常談的話(huà)題,當(dāng)應(yīng)用程序發(fā)生未捕獲的異常時(shí),Uncaught(in promise) error是其中最常見(jiàn)的錯(cuò)誤類(lèi)型,這篇文章將從多個(gè)方面詳細(xì)闡述這種錯(cuò)誤類(lèi)型的原因與解決方案,感興趣的朋友一起看看吧2023-12-12