二進位制陣列實戰 - 純前端匯出Excel檔案

騰訊IVWEB團隊發表於2019-01-06

以往在處理資料匯出相關工作時,個人習慣使用指令碼語言來完成,例如nodejs、ruby等,但它們對環境都有一定依賴。在瀏覽器的環境下,如何完成該型別操作?下面會給出一種簡單且相容性較好的方案。

Excel的基本概念

在進行Excel匯出之前,先介紹一下它的基本概念:

  • Workbook 每個Workbook對應一個Excel檔案

  • Worksheet 一個Excel檔案中可以同時包含多個Worksheet

使用工具

這次我們會選用SheetJS來進行Excel表格的匯出

二進位制陣列實戰 - 純前端匯出Excel檔案

這是一個同時適用於Browser/Nodejs環境的電子表格編輯庫,主要功能包括:

  • 讀取並解析Excel檔案
  • 編輯表格內容
  • 將資料以Excel檔案形式匯出

操作流程

使用SheetJS進行Excel檔案的匯出大致可以分為以下幾步:

Step1.組織資料

首先我們將需要匯出的資料組織好,推薦使用模板引擎生成,最終形成一個table節點,形如:

    <table id="user_info">
    	<thead>
    		<tr>
    			<th>序號</th>
    			<th>名字</th>
    			<th>性別</th>
    			<th>愛好</th>
    		</tr>
    	</thead>
    	<tbody>
    		<tr>
    			<td>1</td>
    			<td>Alice</td>
    			<td>女</td>
    			<td>看電影</td>
    		</tr>
    		<tr>
    			<td>2</td>
    			<td>Zacks</td>
    			<td>男</td>
    			<td>看書</td>
    		</tr>
    	</tbody>
    </table>
複製程式碼

Step2.使用SheetJS將dom節點或html文字轉換成Workbook

// 生成一個新的workbook,然後往workbook追加worksheet
const cleanWorkbook = XLSX.utils.book_new();
const table = document.getElementById('user_info');
const worksheet = XLSX.utils.table_to_sheet(table);
XLSX.utils.book_append_sheet(cleanWorkbook, worksheet, "sheet2");

// 只需要一個worksheet的時候可以直接read method生成workbook,此時worksheet名稱預設為"Sheet1"
const directWorkbook = XLSX.read(table.outerHTML, {
	type: 'string'
});

複製程式碼

Step3.將workbook轉換為二進位制

const stringToArrayBuffer = function (string) {
	const buffer = new ArrayBuffer(string.length);
	const view = new Uint8Array(buffer);
	for (let i = 0, i !== string.length; ++i) {
		view[i] = string.charCodeAt(i) & 0xFF;
	}
	return buffer;
}
const ab = stringToArrayBuffer(XLSX.write(cleanWorkbook, {
	bookType: 'xlsx',
	type: 'binary'
}));
const tmpDown = new Blob([ab], { type: '' });
複製程式碼

Step4.觸發Excel檔案的自動下載

const a = document.createElement('a');
// 利用URL.createObjectURL()方法為a元素生成blob URL
a.href = URL.createObjectURL(tmpDown)  // 建立物件超連結
a.download = 'demo.xlsx';
a.click();
複製程式碼

就這樣,瀏覽器就會將生成的Excel檔案自動下載到本地,下面是實際效果。

二進位制陣列實戰 - 純前端匯出Excel檔案

二進位制陣列

在上面的例子裡面,我們使用了ArrayBuffer進行二進位制資料的操縱,下面簡單展開一下:

使用過WebGL的同學應該知道,這是瀏覽器與顯示卡之間的通訊介面,為了滿足JavaScript與顯示卡之間大量且實時的資料交換,它們之間的通訊資料必須是二進位制,而不能是傳統的文字格式。如果以文字格式傳遞一個32位整數,兩端都要進行資料轉換,這個部分的時間損耗是不可忽略的,因此願景還是能夠直接傳輸二進位制資料,二進位制陣列就是在這個背景之下誕生的。

它的組成有以下三部分:

  • ArrayBuffer物件: 代表記憶體之中的一段二進位制資料,但不能直接操作,必須通過建立檢視來進行資料操縱。
  • TypedArray物件: 通過傳遞ArrayBuffer的例項生成對應的記憶體檢視,檢視的資料格式共有9種,例如:Uint8Array(無符號8位整數)陣列檢視, Int16Array(16位整數)陣列檢視, Float32Array(32位浮點數)陣列檢視。
  • DataView物件: 與TypedArray物件類似,不同的地方在於這個物件可以自定義格式和位元組序,比如第一個位元組是Uint8(無符號8位整數)、第二個位元組是Int16(16位整數)、第三個位元組是Float32(32位浮點數)等等。
const stringToArrayBuffer = function (string) {
    const buffer = new ArrayBuffer(string.length);
    const view = new Uint8Array(buffer);
    for (let i = 0, i !== string.length; ++i) {
        view[i] = string.charCodeAt(i) & 0xFF;
    }
    return buffer;
}
複製程式碼

在這個轉換函式裡面,我們先是通過ArrayBuffer申請了一段與待轉換字串位元組數等長的記憶體,然後通過建立Uint8的檢視將二進位制資料按位元組裝載到這段記憶體裡面,這就是一個比較簡單的js二進位制資料操縱例子。

小結

通過上面的介紹,我們可以發現純前端進行資料匯出還是比較簡單的。 在日常的使用中,我們需要針對不同場景來進行技術選型,從架構搭建的成本來看,純前端的實現方案能夠在不依賴服務端能力和網路的情況下完成資料匯出。雖然如此,資料量較大的時候,站在效能及使用者互動體驗的角度考慮,在服務端完成會是更優雅的解法。

相關文章