最近业务上有数据大屏的需要,要求不仅能展现数据,同时能提供所选日期范畴的数据下载。本文纯记录实现计划作为笔记,实现细节非常不齐备。
工具库
xlsx 电子表格的标准规范详见:Full XML Schema。上面两个库都基于这个标准实现了这类格式文件的读写(salute!∠(°ゝ°))。
SheetJS
SheetJS 是用于多种电子表格格局的解析器和编写器。通过官网标准、相干文档以及测试文件实现简洁的 JS 办法。SheetJS 强调解析和编写的持重,其跨格局的特点和对立的 JS 标准兼容,并且 ES3/ES5 浏览器向后兼容 IE6。
excelize
Go 语言编写的能够读写电子表格类型文件的公共库
更静默:webworker
Web Worker 为 Web 内容在后盾线程中运行脚本提供了一种简略的办法。线程能够执行工作而不烦扰用户界面。
咱们将 SheetJS 解决数据、生成表格数据(book 类型数据)的流程另起一个线程实现。(尽管另起一个线程从体验上不会适度影响主 UI 线程,但自身启动老本比拟高)。
该组件的目录如下
NewDashboard
├── components
│ ├── LongCard
│ │ ├── echartsOption.ts
│ │ ├── index.tsx
│ │ └── style.module.less
│ └── ShortCard
│ ├── echartsOption.ts
│ ├── index.tsx
│ └── style.module.less
├── index.tsx # 在该文件与 webworker 通信
├── makeTable.ts # 在该文件实现 webworker
└── style.module.less
mdn 给的 samples 的 worker 都是加载内部代码的。在咱们这种组织目录下,worker 应该在一个文件内实现,并导出一个 worker 实例。这里须要借助 URL.createObjectURL(blob) 结构一个外链。
代码如下:
// @file makeTable.ts
const blob = new Blob(
[
`
importScripts('https://g.alicdn.com/code/lib/xlsx/0.17.4/xlsx.full.min.js');
const GOODS_EFFECT_TITLE = [
'开播工夫',
'下播工夫',
'直播间',
'商品名称',
'商品',
'点击人数',
'成交人数',
'粉丝成交比例',
'疏导成交金额',
];
// 接管主过程的表格数据
onmessage = function({data}) {console.log('from main routine', data);
const book = XLSX.utils.book_new();
const sheet = XLSX.utils.aoa_to_sheet([GOODS_EFFECT_TITLE, ...data]);
XLSX.utils.book_append_sheet(book, sheet, '工作表 1');
// book 的数据回传给主过程
postMessage({book});
};
`,
],
{type: 'text/javascript'},
);
export const worker = new Worker(URL.createObjectURL(blob));
留神几个点:
- 因为在 worker 内没有 DOM、windows 等对象,所以没有方法间接应用 XLSX.utils.table_to_book 办法将 table 元素间接导出为 xlsx 表格数据。
- importScript 办法是并行加载所有列出的资源,但执行是同步的。这里须要将 SheetJS 的资源加载进 worker 里。
- 主过程的办法:
// @file index.tsx
import {worker} from './makeTable';
function download() {
// aoa_to_sheet 办法须要一个二维数组来造成电子表格
worker.postMessage([[1, 2, 3]]);
worker.onmessage = ({data}) => {window.XLSX.writeFile(data.book, '测试.xlsx');
};
}
更高速:WebAssembly
对于网络平台而言,WebAssembly 具备微小的意义——它提供了一条路径,以使得以各种语言编写的代码都能够以靠近原生的速度在 Web 中运行。在这种状况下,以前无奈以此形式运行的客户端软件都将能够运行在 Web 中。
咱们应用 Go 语言编译为 wasm 文件,外围代码如下:
// wasm.go
func main() {c := make(chan struct{}, 0)
// js 全局办法 makeExcel
js.Global().Set("makeExcel", js.FuncOf(jsMakeExcel))
// 确保 Go 程序不退出
<-c
}
func makeExcel() []uint8 {f := excelize.NewFile()
f.SetCellValue("Sheet1", "开播工夫", now.Format(time.ANSIC))
f.SetCellValue("Sheet1", "直播间", 1111)
// 在 js 环境中无奈实现文件的操作
// if err := f.SaveAs("simple.xlsx"); err != nil {// log.Fatal((err))
// }
buf, _ := f.WriteToBuffer()
res := make([]uint8, buf.Len())
buf.Read(res)
return res
}
func jsMakeExcel(arg1 js.Value, arg2 []js.Value) interface{} {buf := makeExcel()
js_uint := js.Global().Get("Uint8Array").New(len(buf))
js.CopyBytesToJS(js_uint, buf)
//go 的 uint8 无奈间接回传,须要创立 js 环境的 Uint8Array 类型数据并回传
return js_uint
}
将编译好的 wasm 文件加载进 js 环境
- 引入桥接代码:https://github.com/golang/go/…。此时 window 下会有一个全局构造函数:Go
- 样板代码——实例化 webassembly:
// WebAssembly.instantiateStreaming is not currently available in Safari
if (WebAssembly && !WebAssembly.instantiateStreaming) {
// polyfill
WebAssembly.instantiateStreaming = async (resp, importObject) => {const source = await (await resp).arrayBuffer();
return await WebAssembly.instantiate(source, importObject);
};
}
const go = new Go();
fetch('path/to/wasm.wasm')
.then((response) => response.arrayBuffer())
.then((bytes) => WebAssembly.instantiate(bytes, go.importObject))
.then((res) => go.run(res.instance))
- 实现文件下载
function download() {
// 与一般办法一样调用 go 写入全局的办法,拿到刚刚回传的 uint8array 数据
const buf = makeExcel();
// 创立下载链接,留神文件类型,并下载文件
const blob = new Blob([buf], {type: 'application/vnd.ms-excel',});
const url = URL.createObjectURL(blob);
console.log({blob, str});
const a = document.createElement('a');
a.download = 'test.xlsx';
a.href = url;
a.click();}
既要又要
webworker 和 webassembly 是能够一起应用的,待补充……