——————————☆☆☆——————————
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/ 处取得。