——————————☆☆☆——————————
Node 系列相应地址:
- 代码仓库:https://github.com/LiangJunro...
- 文章仓库:https://github.com/LiangJunro...系列-前端材料/Node
——————————☆☆☆——————————
在通过 Puppeteer 操作浏览器下载到 Excel 之后,咱们终于能够将准备将多语言的操作玩出花来了。
本篇咱们将通过 node-xlsx
,对 Excel 进行多语言导入导出的操作。
一 前言
在服务端的工作中,生成报表并送给经营、产品进行剖析应该是一门简略手艺。
然而在前端中,能这样耍的机会并不多,所以多语言操作是个好玩的点(没接触过的会感觉比拟陈腐)。
当然,既然服务端能够,对 Node.js 来说,提供这种性能也无可非议。
jsliang 十分懒,所以直奔主题关上 GitHub:
那就第 1 个了,不要搞什么调研不调研的,对于非生产数据来说,我就是玩~
看第一行简介:Excel file parser/builder that relies on js-xlsx.
js-xlsx
?这个我晓得啊,在 2021.06.03
这一刻有 25.7k
Star 的仓库地址:https://github.com/SheetJS/sheetjs
其实一开始试了下它对于 Node 的,enm...一时半会没入门!
然而,我还是用我的 node-xlsx
吧,毕竟例子都在它仓库的 README.md 贴出来了!
二 疾速开始
- 安装包:
npm i node-xlsx -S
- 装置 TypeScript:
npm i @types/node-xlsx -D
2.1 测试导入
src/index.ts
import program from 'commander';import common from './common';import './base/console';import xlsx from 'node-xlsx';import fs from 'fs';program .version('0.0.1') .description('工具库')program .command('jsliang') .description('jsliang 帮忙指令') .action(() => { common(); });program .command('test') .description('测试频道') .action(async () => { // 测试新性能的时候应用 // 以 buffer 模式导入 const workSheetsFromBuffer = xlsx.parse(fs.readFileSync(`${__dirname}/common/dist/Excel 试用文件.xlsx`)); console.log(JSON.stringify(workSheetsFromBuffer, null, 2)); // 以文件模式导入 const workSheetsFromFile = xlsx.parse(`${__dirname}/common/dist/Excel 试用文件.xlsx`); console.log(JSON.stringify(workSheetsFromFile, null, 2)); });program.parse(process.argv);
执行 npm run test
,控制台打印如下:
---1---[ { "name": "Sheet1", "data": [ [ "key", "zh-CN", "en-US", "zh-TW", "zh-GZ" ], [ "noMoney", "我没钱啦!", "I have no money", "我沒錢啦!", "我冇钱啦!" ] ] }]---2---[ { "name": "Sheet1", "data": [ [ "key", "zh-CN", "en-US", "zh-TW", "zh-GZ" ], [ "noMoney", "我没钱啦!", "I have no money", "我沒錢啦!", "我冇钱啦!" ] ] }]
OK,都能失常导入~
2.2 测试导出
import program from 'commander';import common from './common';import './base/console';import xlsx from 'node-xlsx';import fs from 'fs';program .version('0.0.1') .description('工具库')program .command('jsliang') .description('jsliang 帮忙指令') .action(() => { common(); });program .command('test') .description('测试频道') .action(async () => { // 测试新性能的时候应用 // 导出数据 const data = [ [1, 2, 3], [true, false, null, 'sheetjs'], ['foo', 'bar', new Date('2014-02-19T14:30Z'), '0.3'], ['baz', null, 'qux'], ]; const buffer = xlsx.build([{ name: "jsliang", data: data }]); // 拿到文件 buffer // 写入文件 fs.writeFileSync(`${__dirname}/common/dist/test-sheet.xlsx`, Buffer.from(buffer)); });program.parse(process.argv);
执行 npm run test
后,目录变成:
关上这个 Excel 文件,能够看到:
好的,导出也 OK 了~
2.3 测试定制宽度
当然,有时候产品十分懒,须要咱们将表格宽度给做好成每一列都能宽一点,那就要定制下页面宽度:
index.ts
import program from 'commander';import common from './common';import './base/console';import xlsx from 'node-xlsx';import fs from 'fs';program .version('0.0.1') .description('工具库')program .command('jsliang') .description('jsliang 帮忙指令') .action(() => { common(); });program .command('test') .description('测试频道') .action(async () => { // 测试新性能的时候应用 // 导出数据 const data = [ ['key', 'zh-CN', 'en-US', 'zh-TW', 'zh-GZ'], ['noMoney', '我没钱啦!', 'I have no money', '我沒錢啦!', '我冇钱啦!'], ]; // 列宽设置 const options = { '!cols': [ { wch: 10 }, { wch: 15 }, { wch: 15 }, { wch: 15 }, { wch: 15 }, ] } // 生成 buffer const buffer = xlsx.build([{ name: "jsliang", data: data }], options); // 拿到文件 buffer // 写入文件 fs.writeFileSync(`${__dirname}/common/dist/Excel 导出文件.xlsx`, Buffer.from(buffer)); });program.parse(process.argv);
执行 npm run test
,看到 dist
目录生成:
而后点开「Excel 导出文件.xlsx」,外面内容为:
劳碌,满屏飘满 no money~
三 多语言操作
在咱们简略理解 node-xlsx
之后,咱们就能够通过它实现多语言的导入导出,以及下一章会解说如何获取须要的资源。
3.1 导入
接「006 - Puppeteer」,咱们在上一篇文章曾经实现了资源的下载,实际上咱们应该一条龙服务,从下载到导入通通给安顿了。
那么,咱们以后的目录须要革新一番:
- src + base - common - language + dist - download.ts - export.ts - import.ts - source.json - index.ts - questionList.ts - sortCatalog.ts - index.ts
文字目录如同没那么清晰,还是贴个图吧:
那么,开始写代码:
questionList.ts - 先明确本人的发问路线
// common 板块的问题征询路线export const questionList = { '公共服务': { // q0 '文件排序': { // q1 '须要排序的文件夹': 'Work 工作', // q2 }, }, '多语言': { // q0 '下载多语言资源': { // q3 '下载地址': 'Work 工作', // q4 }, '导入多语言资源': { // q3 '下载地址': 'Work 工作', // q4 }, '导出多语言资源': { // q3 '导出全量资源': 'Work 工作', '导出单门资源': 'Work 工作', } },};
index.ts
import { inquirer } from '../base/inquirer';import { Result } from '../base/interface';import { sortCatalog } from './sortCatalog';import { downLoadExcel } from './language/download';import { importLanguage } from './language/import';import { exportLanguage } from './language/export';// 问题记录器const answers = { q0: '', q1: '', q2: '', q3: '', q4: '',};const common = (): void => { // 问题路线:看 questionList.ts const questionList = [ // q0 { type: 'list', message: '请问须要什么服务?', choices: ['公共服务', '多语言'] }, // q1 { type: 'list', message: '以后公共服务有:', choices: ['文件排序'] }, // q2 { type: 'input', message: '须要排序的文件夹为?(绝对路径)', }, // q3 { type: 'list', message: '请问多语言须要什么反对?', choices: [ '下载多语言资源', '导入多语言资源', '导出多语言资源', ], }, // q4 { type: 'input', message: '资源下载地址(HTTP)?', default: 'https://www.kdocs.cn/l/sdwvJUKBzkK2', } ]; const answerList = [ // q0 - 请问须要什么服务? async (result: Result, questions: any) => { answers.q0 = result.answer; switch (result.answer) { case '公共服务': questions[1](); break; case '多语言': questions[3](); break; default: break; } }, // q1 - 以后公共服务有: async (result: Result, questions: any) => { answers.q1 = result.answer; if (result.answer === '文件排序') { questions[2](); } }, // q2 - 须要排序的文件夹为?(绝对路径) async (result: Result, _questions: any, prompts: any) => { answers.q2 = result.answer; const sortResult = await sortCatalog(result.answer); if (sortResult) { console.log('排序胜利!'); prompts.complete(); } }, // q3 - 请问多语言须要什么反对? async (result: Result, questions: any, prompts: any) => { answers.q3 = result.answer; switch (result.answer) { case '下载多语言资源': case '导入多语言资源': questions[4](); break; case '导出多语言资源': const exportResult = await exportLanguage(); if (exportResult) { console.log('导出胜利!'); prompts.complete(); } default: break; } }, // q4 - 资源下载地址(HTTP)? async (result: Result) => { answers.q4 = result.answer; const download = async (): Promise<any> => { const downloadResult = await downLoadExcel(result.answer); if (downloadResult) { console.log('下载胜利!'); return true; } }; switch (answers.q3) { case '下载多语言资源': await download(); break; case '导入多语言资源': await download(); const importResult = await importLanguage(); if (importResult) { console.log('导入结束!'); } default: break; } }, ]; inquirer(questionList, answerList);};export default common;
须要留神的是,咱们如果要导入的话,必定有个对应的资源文件,这边就用 source.json
演示:
source.json
{ "zh-CN": { }, "en-US": { }, "zh-TW": { }, "zh-GZ": { }}
简版内容如下,通过 import.ts
导入资源并填充外面内容:
import.ts
import xlsx from 'node-xlsx';import fs from 'fs';import path from 'path';export const importLanguage = async (): Promise<boolean> => { const language = JSON.parse(fs.readFileSync(path.join(__dirname, './source.json'), 'utf8')); const workSheetsFromBuffer = xlsx.parse( fs.readFileSync( path.join(__dirname, '/dist/Excel 试用文件.xlsx'), ), ); const sheet1Data = workSheetsFromBuffer[0].data.map(i => i.map(j => String(j))); // 获取头部数据 const header = sheet1Data[0]; // 查找 key 对应列 let keyIndex = 0; for (let i = 0; i < header.length; i++) { if (header[i] === 'key') { keyIndex = i; break; } } if (keyIndex < 0) { console.error('未找到 key 对应列!'); return false; } // 设置资源内容 const fullLanguage: any[] = [...Object.keys(language), ...header.filter((item: any) => item !== 'key')]; const filterFullLanguage = new Set(); for (let i = 0; i < fullLanguage.length; i++) { if (!filterFullLanguage.has(fullLanguage[i])) { filterFullLanguage.add(fullLanguage[i]); // 如果没有该种语言,则新增 if (!language[fullLanguage[i]]) { language[fullLanguage[i]] = {}; } } } // 获取内容数据 const body = sheet1Data.slice(1); for (let i = 0; i < body.length; i++) { for (let j = 0; j < body[i].length; j++) { if (j !== keyIndex) { const nowLanguage = language[header[j]]; // 一个损耗性能的操作,每次都会读取新列表,然而我不想优化 const nowKey = body[i][keyIndex]; // 获取这一行的 key nowLanguage[nowKey] = body[i][j]; // 替换 key } } } fs.writeFileSync(path.join(__dirname, './source.json'), JSON.stringify(language, null, 2), 'utf8'); return true;};
export.ts
export const exportLanguage = async (): Promise<boolean> => { // 具体内容待补充 return await true;};
编写结束,执行 npm run jsliang
,依照发问一一回车:
而后代码跑起来(姿态很帅),胜利导入:
这样导入流程就结束了。
当然,导入的过程中,还须要修复对齐 key(即某中文 key 状况下,其余资源未翻译;或者删除 key 资源),这些就不颤抖列举了,须要的时候补充写一写,也不难~
3.2 导出
导入尚且如此,导出就更轻松了:
export.ts
import xlsx from 'node-xlsx';import fs from 'fs';import path from 'path';export const exportLanguage = async (): Promise<boolean> => { const languageData = JSON.parse(fs.readFileSync(path.join(__dirname, './source.json'), 'utf8')); // 组装头部数据 const header = Object.keys(languageData); // 组装内容数据 const chineseKeyList = Object.keys(languageData['zh-CN']); const body: any[] = []; for (let i = 0; i < chineseKeyList.length; i++) { const nowKey = chineseKeyList[i]; const nowFloor = [nowKey]; console.log(nowFloor, nowKey); for (let j = 0; j < header.length; j++) { const nowLanguage = header[j]; nowFloor.push(languageData[nowLanguage][nowKey]); } body.push(nowFloor); } // 导出数据 const data = [ ['keys', ...header], ...body, ]; const buffer = xlsx.build([{ name: "jsliang", data: data }]); // 拿到文件 buffer // 写入文件 fs.writeFileSync(path.join(__dirname, './dist/Excel 导出文件.xlsx'), Buffer.from(buffer)); return await true;};
执行 npm run jsliang
,按流程点点:
而后就看下 dist
目录有没有对应的文件:
在关上文件看看:
OK,搞定,出工~
四 后续
那么,Excel 的操作流程咱们就安顿得明明白白了。
再往下一章,jsliang 可能开启 Node 服务,实现简略网站的搭建,不过 jsliang 于 2018 年写过一篇 Node 从 0 根底到企业官网的文章了,所以咱们尝试搞个小游戏吧,嘿嘿~
以后阶段算上 Node 初篇结束,次要也没啥内容,后续会补充开启服务,WebSocket 等内容,冲鸭~
五 参考文献
- nodejs 实现导出 excel 报表
- GitHub:SheetJS
- GitHub:node-xlsx
jsliang 的文档库由 梁峻荣 采纳 常识共享 署名-非商业性应用-雷同形式共享 4.0 国内 许可协定 进行许可。<br/>基于 https://github.com/LiangJunrong/document-library 上的作品创作。<br/>本许可协定受权之外的应用权限能够从 https://creativecommons.org/licenses/by-nc-sa/2.5/cn/ 处取得。