簡介
node端將數(shù)據(jù)生成xlsx文件祷蝌,前端點擊下載痒钝。
項目源碼:https://github.com/linwalker/output-xlsx-demo
操作
- 下載代碼
- node >= 7.8
- npm install
- node index.js
- 訪問localhost: 5000
xlsx
js-xlsx是目前處理js處理excel比較好用的一個庫,生成xlsx只要調(diào)用XLSX.writeFile(workbook, filename)
鸯隅。
workbook是一個對象澜建,結(jié)構(gòu)如下:
//workbook
{
SheetNames: ['sheet1'],
Sheets: {
// worksheet
'sheet1': {
'!ref': 'A1:D4',// 必須要有這個范圍才能輸出,否則導(dǎo)出的 excel 會是一個空表
// cell
'A1': { ... },
// cell
'A2': { ... },
...
}
}
}
用法
只要將需要生成xlsx文件的數(shù)據(jù)蝌以,調(diào)整成上面workbook對象格式炕舵,再調(diào)用XSLX.writeFile(workbook, filename)方法就可以。
node 服務(wù)
node服務(wù)文件index跟畅,一個簡單的頁面渲染和下載請求處理咽筋。
const Koa = require('koa');
const Router = require('koa-router');
const fs = require('fs');
const path =require('path');
const views = require('koa-views');
const dlXlsx = require('./dlXlsx.js');
const app = new Koa();
const router = new Router();
//加載模版引擎
app.use(views(path.join(__dirname, './views'), {
extension: 'html'
}))
//頁面渲染
router.get('/', async (ctx) => {
await ctx.render('main');
})
//下載請求處理
router.get('/download', async (ctx) => {
//生成xlsx文件
await dlXlsx();
//類型
ctx.type = '.xlsx';
//請求返回,生成的xlsx文件
ctx.body = fs.readFileSync('output.xlsx');
//請求返回后碍彭,刪除生成的xlsx文件晤硕,不刪除也行,下次請求回覆蓋
fs.unlink('output.xlsx');
})
// 加載路由中間件
app.use(router.routes()).use(router.allowedMethods())
app.listen(5000);
node服務(wù)基于koa2框架庇忌,node>=7.8舞箍,可以直接食用async和await處理異步請求。
xlsx生成處理
xlsx生成在dlXlsx.js中處理
//dlXlsx.js
const XLSX = require('xlsx');
//表頭
const _headers = ['id', 'name', 'age', 'country'];
//表格數(shù)據(jù)
const _data = [
{
id: '1',
name: 'test1',
age: '30',
country: 'China',
},
...
];
const dlXlsx = () => {
const headers = _headers
.map((v, i) => Object.assign({}, { v: v, position: String.fromCharCode(65 + i) + 1 }))
// 為 _headers 添加對應(yīng)的單元格位置
// [ { v: 'id', position: 'A1' },
// { v: 'name', position: 'B1' },
// { v: 'age', position: 'C1' },
// { v: 'country', position: 'D1' },
.reduce((prev, next) => Object.assign({}, prev, { [next.position]: { v: next.v } }), {});
// 轉(zhuǎn)換成 worksheet 需要的結(jié)構(gòu)
// { A1: { v: 'id' },
// B1: { v: 'name' },
// C1: { v: 'age' },
// D1: { v: 'country' },
const data = _data
.map((v, i) => _headers.map((k, j) => Object.assign({}, { v: v[k], position: String.fromCharCode(65 + j) + (i + 2) })))
// 匹配 headers 的位置皆疹,生成對應(yīng)的單元格數(shù)據(jù)
// [ [ { v: '1', position: 'A2' },
// { v: 'test1', position: 'B2' },
// { v: '30', position: 'C2' },
// { v: 'China', position: 'D2' }],
// [ { v: '2', position: 'A3' },
// { v: 'test2', position: 'B3' },
// { v: '20', position: 'C3' },
// { v: 'America', position: 'D3' }],
// [ { v: '3', position: 'A4' },
// { v: 'test3', position: 'B4' },
// { v: '18', position: 'C4' },
// { v: 'Unkonw', position: 'D4' }] ]
.reduce((prev, next) => prev.concat(next))
// 對剛才的結(jié)果進行降維處理(二維數(shù)組變成一維數(shù)組)
// [ { v: '1', position: 'A2' },
// { v: 'test1', position: 'B2' },
// { v: '30', position: 'C2' },
// { v: 'China', position: 'D2' },
// { v: '2', position: 'A3' },
// { v: 'test2', position: 'B3' },
// { v: '20', position: 'C3' },
// { v: 'America', position: 'D3' },
// { v: '3', position: 'A4' },
// { v: 'test3', position: 'B4' },
// { v: '18', position: 'C4' },
// { v: 'Unkonw', position: 'D4' },
.reduce((prev, next) => Object.assign({}, prev, { [next.position]: { v: next.v } }), {});
// 轉(zhuǎn)換成 worksheet 需要的結(jié)構(gòu)
// { A2: { v: '1' },
// B2: { v: 'test1' },
// C2: { v: '30' },
// D2: { v: 'China' },
// A3: { v: '2' },
// B3: { v: 'test2' },
// C3: { v: '20' },
// D3: { v: 'America' },
// A4: { v: '3' },
// B4: { v: 'test3' },
// C4: { v: '18' },
// D4: { v: 'Unkonw' }
// 合并 headers 和 data
const output = Object.assign({}, headers, data);
// 獲取所有單元格的位置
const outputPos = Object.keys(output);
// 計算出范圍
const ref = outputPos[0] + ':' + outputPos[outputPos.length - 1];
// 構(gòu)建 workbook 對象
const workbook = {
SheetNames: ['mySheet'],
Sheets: {
'mySheet': Object.assign({}, output, { '!ref': ref })
}
};
// 導(dǎo)出 Excel
XLSX.writeFile(workbook, 'output.xlsx')
}
參考
本文主要參考這篇文章