本文節選自 Awesome CheatSheet/DOM CheatSheet,主要是對 DOM 操作中常見的 Blob、File API 相關概念進行簡要描述。
Web 開發中 Blob 與 FileAPI 使用簡述
Blob 是 JavaScript 中的物件,表示不可變的類檔案物件,裡面可以儲存大量的二進位制編碼格式的資料。Blob 物件的建立方式與其他並無區別,建構函式可接受資料序列與型別描述兩個引數:
const debug = { hello: 'world' };
let blob = new Blob([JSON.stringify(debug, null, 2)], {
type: 'application/json'
});
// Blob(22) {size: 22, type: "application/json"}
// 也可以轉化為類 URL 格式
const url = URL.createObjectURL(blob);
// "blob:https://developer.mozilla.org/88c5b6de-3735-4e02-8937-a16cc3b0e852"
// 設定自定義的樣式類
blob = new Blob(['body { background-color: yellow; }'], {
type: 'text/css'
});
link = document.createElement('link');
link.rel = 'stylesheet';
//createObjectURL returns a blob URL as a string.
link.href = URL.createObjectURL(blob);
複製程式碼
其他的型別轉化為 Blob 物件可以參考 covertToBlob.js,將 Base64 編碼的字串或者 DataUrl 轉化為 Blob 物件。Blob 包括了 size 與 type,以及常用的用於擷取的 slice 方法等屬性。Blob 物件能夠新增到表單中,作為上傳資料使用:
const content = '<a id="a"><b id="b">hey!</b></a>'; // the body of the new file...
const blob = new Blob([content], { type: 'text/xml' });
formData.append('webmasterfile', blob);
複製程式碼
slice 方法會返回一個新的 Blob 物件,包含了源 Blob 物件中指定範圍內的資料。其實就是對這個 blob 中的資料進行切割,我們在對檔案進行分片上傳的時候需要使用到這個方法,即把一個需要上傳的檔案進行切割,然後分別進行上傳到伺服器:
const BYTES_PER_CHUNK = 1024 * 1024; // 每個檔案切片大小定為1MB .
const blob = document.getElementById('file').files[0];
const slices = Math.ceil(blob.size / BYTES_PER_CHUNK);
const blobs = [];
Array.from({ length: slices }).forEach(function(item, index) {
blobs.push(blob.slice(index, index + 1));
});
複製程式碼
這裡我們使用的 blob 物件實際上是 HTML5 中的 File 物件;HTML5 File API 允許我們對本地檔案進行讀取、上傳等操作,主要包含三個物件:File,FileList 與用於讀取資料的 FileReader。File 物件就是 Blob 的分支,或者說子集,表示包含某些後設資料的單一檔案物件;FileList 即是檔案物件的列表。FileReader 能夠用於從 Blob 物件中讀取資料,包含了一系列讀取檔案的方法與事件回撥,其基本用法如下:
const reader = new FileReader();
reader.addEventListener('loadend', function() {
// reader.result 包含了 Typed Array 格式的 Blob 內容
});
reader.readAsArrayBuffer(blob);
blob = new Blob(['This is my blob content'], { type: 'text/plain' });
read.readAsText(bolb); // 讀取為文字
// reader.readAsArrayBuffer //將讀取結果封裝成 ArrayBuffer ,如果想使用一般需要轉換成 Int8Array 或 DataView
// reader.readAsBinaryString // 在IE瀏覽器中不支援改方法
// reader.readAsTex // 該方法有兩個引數,其中第二個引數是文字的編碼方式,預設值為 UTF-8
// reader.readAsDataURL // 讀取結果為DataURL
// reader.readyState // 上傳中的狀態
複製程式碼
在圖片上傳中,我們常常需要獲取到本地圖片的預覽,參考 antd/Upload 中的處理:
// 將檔案讀取為 DataURL
const previewFile = (file: File, callback: Function) => {
const reader = new FileReader();
reader.onloadend = () => callback(reader.result);
reader.readAsDataURL(file);
};
// 設定檔案的 DataUrl
previewFile(file.originFileObj, (previewDataUrl: string) => {
file.thumbUrl = previewDataUrl;
});
// JSX
<img src={file.thumbUrl || file.url} alt={file.name} />;
複製程式碼
另一個常用的場景就是獲取剪貼簿中的圖片,並將其預覽展示,可以參考 coding-snippets/image-paste:
const cbd = e.clipboardData;
const fr = new FileReader();
for (let i = 0; i < cbd.items.length; i++) {
const item = cbd.items[i];
if (item.kind == 'file') {
const blob = item.getAsFile();
if (blob.size === 0) {
return;
}
previewFile(blob);
}
}
複製程式碼
標準的 Web 標準中提供了 FileReader 物件進行讀取操作,不過 Chrome 中提供了 FileWriter 物件,允許我們在瀏覽器沙盒中建立檔案,其基於 requestFileSystem 方法:
// 僅可用於 Chrome 瀏覽器中
window.requestFileSystem =
window.requestFileSystem || window.webkitRequestFileSystem;
window.requestFileSystem(type, size, successCallback, opt_errorCallback);
複製程式碼
簡單的檔案建立與寫入如下所示:
function onInitFs(fs) {
fs.root.getFile(
'log.txt',
{ create: true },
function(fileEntry) {
// Create a FileWriter object for our FileEntry (log.txt).
fileEntry.createWriter(function(fileWriter) {
fileWriter.onwriteend = function(e) {
console.log('Write completed.');
};
fileWriter.onerror = function(e) {
console.log('Write failed: ' + e.toString());
};
// Create a new Blob and write it to log.txt.
var blob = new Blob(['Lorem Ipsum'], { type: 'text/plain' });
fileWriter.write(blob);
}, errorHandler);
},
errorHandler
);
}
window.requestFileSystem(window.TEMPORARY, 1024 * 1024, onInitFs, errorHandler);
複製程式碼