JS: 前端理解base64

Base64 就是一种编码方法,可以将任意值转成 0~9、A~Z、a-z、+和/这64个字符组成的可打印字符。

编码原理

Base64是一种索引编码,每个字符都对应一个索引。字符索引关系表具体如下述数组,数组中成员的下标值即对应的索引。

['A', 'B', 'C', ... 'a', 'b', 'c', ... '0', '1', ... '+', '/']

  0    1    2   ...  26   27  28   ...  52   53  ...  62   63  

下述两种方法都可以生成此字符索引关系数组:

  • 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split('')
  • [].slice.call('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/')

编码规则

  • 将待转的字符串每三个字节分一组,每个字节转为Unicode 码点(二进制表示)对应的是8比特(bit),3个字节一共24个二进制位
  • 24个二进制位重新分组,每6个一组,共4组
  • 每组高位补俩0,此时24变32,共四个字节
  • 每个字节转为十进制得到索引编号,根据字符索引关系表,得到一个四个字节的Base64编码字符。

举例

  •  Hel分别对应的ASCII码为72,101,108(可通过字符串的charCodeAt方法获取)
     'H'.charCodeAt('0')    // 72
     'e'.charCodeAt('0')    // 101
     'l'.charCodeAt('0')    // 108
    72,101,108 分别对应的8位二进制(可通过数值的toString(2)方法获取)
     (72).toString(2).padStart(8,'0')       // '01001000'
    (101).toString(2).padStart(8,'0')       // '01100101'
    (108).toString(2).padStart(8,'0')       // '01101100'
  • 24个二进制位重新分组,每6个一组,共4组
  • 每组高位补俩0,此时24变32,共四个字节,即00010010,00000110,00010101,00101100。
    这四个字节对应的十进制即索引编码为:18、6、21、44(可通过0bxxxxxxxx方式转为十进制)
    0b00010010 // 18
    0b00000110 //  6
    0b00010101 // 21
    0b00101100 // 44
  • 对照字符索引关系表,通过下标找到对应的字符。
    const str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
    // const arr = str.split('');
    const arr = Array.prototype.slice.call(str);
    arr[18] // 'S'
    arr[6]  // 'G'
    arr[21] // 'V'
    arr[44] // 's'

        因此: 'Hel' 经Base64编码后得到: 'SGVs'

位数不足的情况

待转字符不总是3的倍数,当字节数不足3时,又该如何?

和三个字节的差异主要体现在重新分组和补位上。

两个字节:共16个二进制位,每6个一组时,第三组不足的两位用0补齐,得到三个编码字符,最后一位用'='补上。'hi' 经Base64编码后得到: 'aGk='。

一个字节:共8个二进制位,每6个一组时,第二组不足的四位用0补齐,得到两个编码字符,最后两位用'='补上。'x' 经Base64编码后得到: 'eA=='。

解码

解码是编码的逆向操作,理解了编码,解码还是比较容易的。这里不展开说明。

编解码方法

1、JavaScript 原生提供两个 Base64 相关的方法

  • btoa() :任意值转为 Base64 编码
  • atob() :Base64 编码转为原来的值
btoa('Hello World!')     // "SGVsbG8gV29ybGQh"
atob('SGVsbG8gV29ybGQh') // "Hello World!"

这两个方法不适合非 ASCII 码的字符,会报错。

btoa('中') // 报错

要将非 ASCII 码字符转为 Base64 编码,必须中间插入一个转码环节,再使用这两个方法。

btoa(encodeURIComponent('中'))           // 'JUU0JUI4JUFE'
decodeURIComponent(atob('JUU0JUI4JUFE')) // '中'

注:如果你的项目要兼容IE6~9,请放弃这俩方法,浏览器不支持。

2、开源的base64

// 下载依赖
npm install --save js-base64

// 使用
import {Base64} from 'js-base64'

Base64.encode('Hello world!')     // 'SGVsbG8gd29ybGQh'
Base64.decode('SGVsbG8gd29ybGQh') // 'Hello world!'
Base64.encode('中')               // '5Lit'

Base64前端应用

1、Base64代替小图标

一些比较小的图标,使用 Base64 编码。浏览器能直接展示Base64编码图片,可以减少 http 请求。

<img data-v-e43c18bc="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAAC..." alt="">

.icon-camera {
    background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAmCAYAAACCjRgBAAAAAXNS...) left top no-repeat;
}

img的src属性或者 background的url属性,指向的不是一个资源地址,而是Data URLs(前缀为 data: 协议的 URL,其允许内容创建者向文档中嵌入小文件)。

// 语法
Data URLs 由四个部分组成:前缀 (data:)、指示数据类型的 MIME 类型、如果非文本则为可选的base64标记、数据本身

data:[<mediatype>][;base64],<data>

Base64特点是编码后体积会变大【至少会增加1/3】。因此,图标编码后会比原图大,图片越大,差别就越大,需约定转码上限。Vue项目中可通过url-loader来配置图标转Base64的大小。

{
  test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
  loader: 'url-loader',
  options: {
    limit: 10000, // 单位B, 约等于10Kb
    name: utils.assetsPath('img/[name].[hash:7].[ext]')
  }
}

2、Vue路由参数的编解码

// 编码
this.$router.push({
  path: '....',
  query: {
    info: Base64.encode(JSON.stringify(param))
  }
})

// 解码
created() {
   let param = JSON.parse(Base64.decode(this.$route.query.info))
}

3、FileReader 对象

FileReader 对象用于读取 File 对象或 Blob 对象所包含的文件内容。

浏览器原生提供一个FileReader构造函数,用来生成 FileReader 实例。

FileReader.readAsDataURL():读取完成后,result属性将返回一个 Data URL 格式(Base64 编码)的字符串,代表文件内容。对于图片文件,这个字符串可以用于<img>元素的src属性。注意,这个字符串不能直接进行 Base64 解码,必须把前缀data:*/*;base64,从字符串里删除以后,再进行解码。

/* HTML 代码如下
  <input type="file" onchange="previewFile()">
  <img src="" height="200">
*/

function previewFile() {
  var preview = document.querySelector('img');
  var file    = document.querySelector('input[type=file]').files[0];
  var reader  = new FileReader();

  reader.addEventListener('load', function () {
    preview.src = reader.result;
  }, false);

  if (file) {
    reader.readAsDataURL(file);
  }
}

上面代码中,用户选中图片文件以后,脚本会自动读取文件内容,然后作为一个 Data URL 赋值给<img>元素的src属性,从而把图片展示出来。

The End

参考连接:

字符串 - JavaScript 教程 - 网道

File 对象,FileList 对象,FileReader 对象 - JavaScript 教程 - 网道

猜你喜欢

转载自blog.csdn.net/weixin_43932309/article/details/126662205