Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
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 屬性也可以在類型化數組的實例上獲?。?/p>
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小時內與您取得聯系。