Blob 全称为 binary large object ,即二进制大对象,它是 JavaScript 中的一个对象,表示原始的类似文件的数据。实际上,Blob 对象是包含有只读原始数据的类文件对象。简单来说,Blob 对象就是一个不可修改的二进制文件。
new Blob(array, options);
array:由 ArrayBuffer、ArrayBufferView、Blob、DOMString 等对象构成的,将会被放进 Blob options:可选的 BlobPropertyBag 字典,它可能会指定如下两个属性。 type:默认值为 "",表示将会被放入到 blob 中的数组内容的 MIME 类型。
这里可以成为动态文件创建,其正在创建一个类似文件的对象。这个 blob 对象上有两个属性:
size:Blob对象中所包含数据的大小(字节)
type:字符串,认为该Blob对象所包含的 MIME 类型
下面来看打印结果:
const blob = new Blob(["Hello World"], {type: "text/plain"});
console.log(blob.size); // 11
console.log(blob.type); // "text/plain"
复制代码
注意,字符串"Hello World"是 UTF-8 编码的,因此它的每个字符占用 1 个字节。
到现在,Blob 对象看起来似乎我们还是没有啥用。那该如何使用 Blob 对象呢?可以使用 URL.createObjectURL() 方法将其转化为一个 URL,并在 Iframe 中加载:
<iframe></iframe>
const iframe = document.getElementsByTagName("iframe")[0];
const blob = new Blob(["Hello World"], {type: "text/plain"});
iframe.src = URL.createObjectURL(blob);
其有三个参数:
start:设置切片的起点,即切片开始位置。默认值为 0,这意味着切片应该从第一个字节开始
end:设置切片的结束点,会对该位置之前的数据进行切片。默认值为blob.size
contentType:设置新 blob 的 MIME 类型。如果省略 type,则默认为 blob 的原始值
const iframe = document.getElementsByTagName("iframe")[0];
const blob = new Blob(["Hello World"], {type: "text/plain"});
const subBlob = blob.slice(0, 5);
iframe.src = URL.createObjectURL(subBlob);
复制代码
此时页面会显示"Hello"。
文件(File)接口提供有关文件的信息,并允许网页中的 JavaScript 访问其内容。实际上,File 对象是特殊类型的 Blob,且可以用在任意的 Blob 类型的 context 中。Blob 的属性和方法都可以用于 File 对象。
在 JavaScript 中,主要有两种方法来获取 File 对象:
<input> 元素上选择文件后返回的 FileList 对象;文件拖放操作生成的 DataTransfer 对象
<input type="file" id="fileInput" multiple="multiple">
这里给 input 标签添加了三个属性:
type="file":指定 input 的输入类型为文件
id="fileInput":指定 input 的唯一 id
multiple="multiple":指定 input 可以同时上传多个文件
下面来给 input 标签添加 onchange 事件,当选择文件并上传之后触发:
const fileInput = document.getElementById("fileInput");
fileInput.onchange = (e) => {
console.log(e.target.files);
}
当点击上传文件时,控制台就会输出一个 FileList 数组,这个数组的每个元素都是一个 File 对象,一个上传的文件就对应一个 File 对象
每个 File 对象都包含文件的一些属性,这些属性都继承自 Blob 对象:
通常,我们在上传文件时,可以通过对比 size 属性来限制文件大小,通过对比 type 来限制上传文件的格式等。
另一种获取 File 对象的方式就是拖放 API,这个 API 很简单,就是将浏览器之外的文件拖到浏览器窗口中,并将它放在一个成为拖放区域的特殊区域中。拖放区域用于响应放置操作并从放置的项目中提取信息。这些是通过 ondrop 和 ondragover 两个 API 实现的。
下面来看一个简单的例子,首先定义一个拖放区域:
<div id="drop-zone"></div>
然后给这个元素添加 ondragover 和 ondrop 事件处理程序:
const dropZone = document.getElementById("drop-zone");
dropZone.ondragover = (e) => {
e.preventDefault();
}
dropZone.ondrop = (e) => {
e.preventDefault();
const files = e.dataTransfer.files;
console.log(files)
}
注意:这里给两个 API 都添加了 e.preventDefault(),用来阻止默认事件。它是非常重要的,可以用来阻止浏览器的一些默认行为,比如放置文件将显示在浏览器窗口中。
当拖放文件到拖放区域时,控制台就会输出一个 FileList 数组,该数组的每一个元素都是一个 File 对象。这个 FileList 数组是从事件参数的 dataTransfer 属性的 files 获取的
FileReader 是一个异步 API,用于读取文件并提取其内容以供进一步使用。FileReader 可以将 Blob 读取为不同的格式。
const reader = new FileReader();
FileReader 对象提供了以下方法来加载文件:
FileReader 对象常用的事件如下:
当然,这些方法可以加上前置 on 后在HTML元素上使用,比如onload、onerror、onabort、onprogress。除此之外,由于FileReader对象继承自EventTarget,因此还可以使用 addEventListener() 监听上述事件。
const fileInput = document.getElementById("fileInput");
const reader = new FileReader();
fileInput.onchange = (e) => {
reader.readAsText(e.target.files[0]);
}
reader.onload = (e) => {
console.log(e.target.result);
}
这里,首先创建了一个 FileReader 对象,当文件上传成功时,使用 readAsText() 方法读取 File 对象,当读取操作完成时打印读取结果。
使用上述例子读取文本文件时,就是比较正常的。如果读取二进制文件,比如png格式的图片,往往会产生乱码. 那该如何处理这种二进制数据呢?readAsDataURL() 是一个不错的选择,它可以将读取的文件的内容转换为 base64 数据的 URL 表示。这样,就可以直接将 URL 用在需要源链接的地方,比如 img 标签的 src 属性。
const fileInput = document.getElementById("fileInput");
const reader = new FileReader();
fileInput.onchange = (e) => {
reader.readAsDataURL(e.target.files[0]);
}
reader.onload = (e) => {
console.log(e.target.result);
}
将上传的图片通过以上方式显示在页面上:
<input type="file" id="fileInput" />
<img id="preview" />
const fileInput = document.getElementById("fileInput");
const preview = document.getElementById("preview");
const reader = new FileReader();
fileInput.onchange = (e) => {
reader.readAsDataURL(e.target.files[0]);
};
reader.onload = (e) => {
preview.src = e.target.result;
console.log(e.target.result);
};
当上传大文件时,可以通过 progress 事件来监控文件的读取进度:
ArrayBuffer 对象用来表示通用的、固定长度的原始二进制数据缓冲区。ArrayBuffer 的内容不能直接操作,只能通过 DataView 对象或 TypedArrray 对象来访问。这些对象用于读取和写入缓冲区内容。
ArrayBuffer 本身就是一个黑盒,不能直接读写所存储的数据,需要借助以下视图对象来读写:
TypedArray视图和 DataView视图的区别主要是字节序,前者的数组成员都是同一个数据类型,后者的数组成员可以是不同的数据类型。
那 ArrayBuffer 与 Blob 有啥区别呢?根据 ArrayBuffer 和 Blob 的特性,Blob 作为一个整体文件,适合用于传输;当需要对二进制数据进行操作时(比如要修改某一段数据时),就可以使用 ArrayBuffer。
ArrayBuffer 有哪些常用的方法和属性。
new ArrayBuffer(bytelength)
ArrayBuffer()构造函数可以分配指定字节数量的缓冲区,其参数和返回值如下:
const buffer = new ArrayBuffer(16);
console.log(buffer.byteLength); // 16
ArrayBuffer 实例上还有一个 slice 方法,该方法可以用来截取 ArrayBuffer 实例,它返回一个新的 ArrayBuffer ,它的内容是这个 ArrayBuffer 的字节副本,从 begin(包括),到 end(不包括)。来看例子:
const buffer = new ArrayBuffer(16);
console.log(buffer.slice(0, 8)); // 16
这里会从 buffer 对象上将前8个字节生成一个新的ArrayBuffer对象。这个方法实际上有两步操作,首先会分配一段指定长度的内存,然后拷贝原来ArrayBuffer对象的置顶部分。
ArrayBuffer 上有一个 isView()方法,它的返回值是一个布尔值,如果参数是 ArrayBuffer 的视图实例则返回 true,例如类型数组对象或 DataView 对象;否则返回 false。简单来说,这个方法就是用来判断参数是否是 TypedArray 实例或者 DataView 实例:
const buffer = new ArrayBuffer(16);
ArrayBuffer.isView(buffer) // false
const view = new Uint32Array(buffer);
ArrayBuffer.isView(view) // true
TypedArray 对象一共提供 9 种类型的视图,每一种视图都是一种构造函数
元素 | 类型化数组 | 字节 | 描述 |
Int8 | Int8Array | 1 | 8 位有符号整数 |
Uint8 | Uint8Array | 1 | 8 位无符号整数 |
Uint8C | Uint8ClampedArray | 1 | 8 位无符号整数 |
Int16 | Int16Array | 2 | 16 位有符号整数 |
Uint16 | Uint16Array | 2 | 16 位无符号整数 |
Int32 | Int32Array | 4 | 32 位有符号整数 |
Uint32 | Uint32Array | 4 | 32 位无符号整数 |
Float32 | Float32Array | 4 | 32 位浮点 |
Float64 | Float64Array | 8 | 64 位浮点 |
这些构造函数生成的对象统称为 TypedArray 对象。它们和正常的数组很类似,都有length 属性,都能用索引获取数组元素,所有数组的方法都可以在类型化数组上面使用。
那类型化数组和数组有什么区别呢?
TypedArray 的语法如下(TypedArray只是一个概念,实际使用的是那9个对象):
new Int8Array(length);
new Int8Array(typedArray);
new Int8Array(object);
new Int8Array(buffer [, byteOffset [, length]]);
TypedArray(typeArray) :接收一个视图实例作为参数
const view = new Int8Array(new Uint8Array(6));
view[0] = 10;
view[3] = 6;
console.log(view);
需要注意,TypedArray视图会开辟一段新的内存,不会在原数组上建立内存。当然,这里创建的类型化数组也能转换回普通数组:
Array.prototype.slice.call(view); // [10, 2, 3, 6, 5]
每种视图的构造函数都有一个 BYTES_PER_ELEMENT 属性,表示这种数据类型占据的字节数:
Int8Array.BYTES_PER_ELEMENT // 1
Uint8Array.BYTES_PER_ELEMENT // 1
Int16Array.BYTES_PER_ELEMENT // 2
Uint16Array.BYTES_PER_ELEMENT // 2
Int32Array.BYTES_PER_ELEMENT // 4
Uint32Array.BYTES_PER_ELEMENT // 4
Float32Array.BYTES_PER_ELEMENT // 4
Float64Array.BYTES_PER_ELEMENT // 8
BYTES_PER_ELEMENT 属性也可以在类型化数组的实例上获取:
const buffer = new ArrayBuffer(16);
const view = new Uint32Array(buffer);
console.log(Uint32Array.BYTES_PER_ELEMENT); // 4
说完 ArrayBuffer,下面来看看另一种操作 ArrayBuffer 的方式:DataView。DataView 视图是一个可以从 二进制 ArrayBuffer 对象中读写多种数值类型的底层接口,使用它时,不用考虑不同平台的字节序问题。
DataView视图提供更多操作选项,而且支持设定字节序。本来,在设计目的上,ArrayBuffer对象的各种TypedArray视图,是用来向网卡、声卡之类的本机设备传送数据,所以使用本机的字节序就可以了;而DataView视图的设计目的,是用来处理网络设备传来的数据,所以大端字节序或小端字节序是可以自行设定的。
const buffer = new ArrayBuffer(16);
const view = new DataView(buffer);
console.log(view);
DataView实例有以下常用属性:
DataView 实例提供了以下方法来读取内存,它们的参数都是一个字节序号,表示开始读取的字节位置:
const buffer = new ArrayBuffer(24);
const view = new DataView(buffer);
// 从第1个字节读取一个8位无符号整数
const view1 = view.getUint8(0);
// 从第2个字节读取一个16位无符号整数
const view2 = view.getUint16(1);
// 从第4个字节读取一个16位无符号整数
const view3 = view.getUint16(3);
DataView 实例提供了以下方法来写入内存,它们都接受两个参数,第一个参数表示开始写入数据的字节序号,第二个参数为写入的数据:
其实 Blob URL/Object URL 是一种伪协议,允许将 Blob 和 File 对象用作图像、二进制数据下载链接等的 URL 源。
对于 Blob/File 对象,可以使用 URL构造函数的 createObjectURL() 方法创建将给出的对象的 URL。这个 URL 对象表示指定的 File 对象或 Blob 对象。我们可以在<img>、<script> 标签中或者 <a> 和 <link> 标签的 href 属性中使用这个 URL。 :
<input type="file" id="fileInput" />
<img id="preview" />
再来使用 URL.createObjectURL() 将File 对象转化为一个 URL:
const fileInput = document.getElementById("fileInput");
const preview = document.getElementById("preview");
fileInput.onchange = (e) => {
preview.src = URL.createObjectURL(e.target.files[0]);
console.log(preview.src);
};
const objUrl = URL.createObjectURL(new File([""], "filename"));
console.log(objUrl);
URL.revokeObjectURL(objUrl);
Base64 是一种基于64个可打印字符来表示二进制数据的表示方法。Base64 编码普遍应用于需要通过被设计为处理文本数据的媒介上储存和传输二进制数据而需要编码该二进制数据的场景。这样是为了保证数据的完整并且不用在传输过程中修改这些数据。
在 JavaScript 中,有两个函数被分别用来处理解码和编码 base64 字符串:
btoa("JavaScript") // 'SmF2YVNjcmlwdA=='
atob('SmF2YVNjcmlwdA==') // 'JavaScript'
那 base64 的实际应用场景有哪些呢?其实多数场景就是基于Data URL的。比如,使用toDataURL()方法把 canvas 画布内容生成 base64 编码格式的图片:
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext("2d");
const dataUrl = canvas.toDataURL();
除此之外,还可以使用readAsDataURL()方法把上传的文件转为base64格式的data URI,比如上传头像展示或者编辑:
<input type="file" id="fileInput" />
<img id="preview" />
const fileInput = document.getElementById("fileInput");
const preview = document.getElementById("preview");
const reader = new FileReader();
fileInput.onchange = (e) => {
reader.readAsDataURL(e.target.files[0]);
};
reader.onload = (e) => {
preview.src = e.target.result;
console.log(e.target.result);
};
另外,一些小的图片都可以使用 base64 格式进行展示,img标签和background的 url 属性都支持使用base64 格式的图片,这样做也可以减少 HTTP 请求。
看完这些基本的概念,下面就来看看常用格式之间是如何转换的。
const blob = new Blob([new Uint8Array(buffer, byteOffset, length)]);
const base64 = btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)));
const base64toBlob = (base64Data, contentType, sliceSize) => {
const byteCharacters = atob(base64Data);
const byteArrays = [];
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
const slice = byteCharacters.slice(offset, offset + sliceSize);
const byteNumbers = new Array(slice.length);
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
const blob = new Blob(byteArrays, {type: contentType});
return blob;
}
function blobToArrayBuffer(blob) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.onerror = () => reject;
reader.readAsArrayBuffer(blob);
});
}
function blobToBase64(blob) {
return new Promise((resolve) => {
const reader = new FileReader();
reader.onloadend = () => resolve(reader.result);
reader.readAsDataURL(blob);
});
}
const objectUrl = URL.createObjectURL(blob);
、Blob(Binary Large Object)定义:二进制类型的大对象数据,在 JavaScript 中 Blob 对象表示不可变的原始数据。
2、语法:
var aBlob = new Blob(blobParts, options);
其中:blobParts是一个由 ArrayBuffer、Blob、DOMString 等对象构成的数组;options是一个可选项,由type和endings组成,type代表了被放入到 blob 中的内容的 MIME 类型,endings用于指定包含行结束符 \n 的字符串如何被表示(native表示行结束符\n被更改为适合宿主操作系统的换行符,transparent会保持 blob 中保存的行结束符不变)。
定义Blob
3、Blob属性和方法:两个只读属性size和type,其中size属性用于表示数据的大小(以字节为单位),type 属性为MIME 类型的字符串。slice([start[, end[, contentType]]])返回一个源指定范围内的Blob 对象;stream()返回一个读取 blob 内容的ReadableStream;text()返回一个 Promise 对象且包含 blob 所有内容的 UTF-8 格式的 USVString;arrayBuffer()返回一个 Promise 对象且包含 blob 所有内容的二进制格式的 ArrayBuffer。
Blob属性和方法
4、Blob URL/Object URL 是一种伪协议,允许 Blob作为链接的URL源,如a.href、img.src等。
创建 Blob URL:url=URL.createObjectURL(Blob),览器器为 URL.createObjectURL 生成的 URL 存储了一个 URL → Blob 映射,此类 URL 较短,例如
blob:http://domain/b3ad7623-60bb-4eff-9b9d-f925438b97c7
Blob 本身仍驻留在内存中,在不需要时,可以调用URL.revokeObjectURL(url)来删除引用。
5、base64也可以作为<img src= />的源,格式为
data:[<mediatype>][;base64],<data>
其中mediatype 是个MIME 类型的字符串,如 image/png,默认值为 text/plain;charset=US-ASCII,例如:
<img src="data:image/png;base64,R0lGODlheABaAPf/AAC...">
lob对象介绍
一个Blob对象表示一个不可变的,原始数据的类似文件对象。Blob表示的数据不一定是一个JavaScript原生格式blob对象本质上是js中的一个对象,里面可以储存大量的二进制编码格式的数据。
创建blob对象
创建blob对象本质上和创建一个其他对象的方式是一样的,都是使用Blob()的构造函数来进行创建。构造函数接受两个参数:
第一个参数为一个数据序列,可以是任意格式的值。
第二个参数是一个包含两个属性的对象{type:MIME的类型,endings:决定第一个参数的数据格式,可以取值为"transparent"或者"native"(transparent的话不变,是默认值,native的话按操作系统转换)。}
Blob()构造函数允许使用其他对象创建一个Blob对象,比如用字符串构建一个blob
既然是对象,那么blob也拥有自己的属性以及方法
属性
布尔值,指示Blob.close()是否在该对象上调用过。关闭的blob对象不可读。
Blob对象中所包含数据的大小(字节)。
一个字符串,表明该Blob对象所包含数据的MIME类型。如果类型未知,则该值为空字符串。
方法
关闭Blob对象,以便能释放底层资源。
返回一个新的Blob对象,包含了源Blob对象中指定范围内的数据。其实就是对这个blob中的数据进行切割,我们在对文件进行分片上传的时候需要使用到这个方法。
看到上面这些方法和属性,使用过HTML5提供的File接口的应该都很熟悉,这些属性和方法在File接口中也都有。其实File接口就是基于Blob,继承blob功能并将其扩展为支持用户系统上的文件,也就是说:
File接口中的Flie对象就是继承与Blob对象。
blob对象的使用
上面说了很多关于Blob对象的一些概念性的东西,下面我们来看看实际用途。
分片上传
首先说说分片上传,我们在进行文件上传的时候,因为服务器的限制,会限制每一次上传到服务器的文件大小不会很大,这个时候我们就需要把一个需要上传的文件进行切割,然后分别进行上传到服务器。
假如需要做到这一步,我们需要解决两个问题:
首先怎么切割的问题上面已经有过说明,因为File文件对象是继承与Blob对象的,因此File文件对象也拥有slice这个方法,我们可以使用这个方法将任何一个File文件进行切割。
代码如下:
通过上面的方法。我们就得到了一个切割之后的File对象组成的数组blobs;
接下来要做的时候就是讲这些文件分别上传到服务器。
在HTTP1.1以上的协议中,有Transfer-Encoding这个编码协议,用以和服务器通信,来得知当前分片传递的文件进程。
这样解决了这两个问题,我们不仅可以对文件进行分片上传,并且能够得到文件上传的进度。
粘贴图片
blob还有一个应用场景,就是获取剪切板上的数据来进行粘贴的操作。例如通过QQ截图后,需要在网页上进行粘贴操作。
粘贴图片我们需要解决下面几个问题
首先我们可以通过paste事件来监听用户的粘贴操作:
然后通过事件对象中的clipboardData对象来获取图片的文件数据。
clipboardData对象介绍
介绍一下clipboardData对象,它实际上是一个DataTransfer类型的对象,DataTransfer是拖动产生的一个对象,但实际上粘贴事件也是它。
clipboardData的属性介绍
items介绍
items是一个DataTransferItemList对象,自然里面都是DataTransferItem类型的数据了。
属性
items的DataTransferItem有两个属性kind和type
方法
在原型上还有一些其他方法,不过在处理剪切板操作的时候一般用不到了。
type介绍
一般types中常见的值有text/plain、text/html、Files。
有了上面这些方法,我们可以解决第二个问题即获取到剪切板上的数据。
最后我们需要将获取到的数据渲染到网页上。
其实这个本质上就是一个类似于上传图片本地浏览的问题。我们可以直接通过HTML5的File接口将获取到的文件上传到服务器然后通过讲服务器返回的url地址来对图片进行渲染。也可以使用fileRender对象来进行图片本地浏览。
fileRender对象简介
从Blob中读取内容的唯一方法是使用FileReader。
FileReader接口有4个方法,其中3个用来读取文件,另一个用来中断读取。无论读取成功或失败,方法并不会返回读取结果,这一结果存储在result属性中。
FileReader接口包含了一套完整的事件模型,用于捕获读取文件时的状态。
通过上面的方法以及事件,我们可以发现,通过readAsDataURL方法及onload事件就可以拿到一个可本地浏览图片的DataURL。
最终代码如下:
这样我们就可以监听到用户的粘贴操作,并且将用户粘贴的图片文件实时的渲染到网页之中了。
总结
以上是我对Blob对象的一些学习分享,希望在实际应用上能对大家有所帮助。也希望大家多多支持小编。
*请认真填写需求信息,我们会在24小时内与您取得联系。