【资料图】
怎么利用node生成word文档?下面本篇文章给大家介绍一下使用node生成word文档的方法,分享一个实用库,聊聊该库的使用方法,希望对大家有所帮助!最近有项目需要用到生成word文档,平时经常用的都是通过模板生成,里面变量使用占位符替换,好处是快捷、方便、简单、不需要通过代码调word样式,确定是很多库不支持图片绘制(很多都是付费功能),找一圈,发现一个很有意思的库,正好也满足我们的需求,特此分享一下
依赖
// https://docx.js.org/#/npm i docx // https://www.npmjs.com/package/downloadnpm i download
说明,因为docx绘图只支持文件流,所以要把网络文件下载到本地转成buffer
代码
话不多说,上代码
import * as fs from "fs"import { Document, Packer, Paragraph, TextRun, ImageRun, HeadingLevel, AlignmentType, convertInchesToTwip, Table, TableRow, TableCell, WidthType, VerticalAlign, BorderStyle } from "docx"const download = require("download")// 性别enum Gender { Male = "male", Female = "female"}// 选手type PlayerSchema = { name: string gender: string idCard?: string birthday?: string weight?: string remark?: string avatar?: string localAvatar?: string level: string}type GroupSchema = { // gender: Gender institution: string leader: string phone: string coach: string doctor: string players: PlayerSchema[]}// 所有数据interface DataSchema { [key: string]: GroupSchema}// 表格无边框const noBoder = { top: { style: BorderStyle.NIL, size: 0, color: "FFFFFF" }, bottom: { style: BorderStyle.NIL, size: 0, color: "FFFFFF" }, left: { style: BorderStyle.NIL, size: 0, color: "FFFFFF" }, right: { style: BorderStyle.NIL, size: 0, color: "FFFFFF" }}// 删除下载的照片及文件夹function delStaticFile(groupNames: string[]) { for (let groupName of groupNames) { if (fs.existsSync(groupName)) { const files = fs.readdirSync(groupName) files.map((file: string) => { let curPath = groupName + "/" + file // 删除选手招聘 fs.unlinkSync(curPath) }) fs.rmdirSync(groupName) } }}// 生成wordasync function generate (data: DataSchema) { const groupNames = Object.keys(data) // 比较粗糙的控制单元格长度逻辑 const longHeaders = ["身份证号", "备注"] // 下载远程资源到本地 for (let groupName of groupNames) { if (!fs.existsSync(groupName)) { fs.mkdirSync(groupName) } const players = data[groupName].players for (let player of players) { if (player.avatar) { const avatarArr = player.avatar.split("/") const fileName = `${groupName}/${avatarArr[avatarArr.length - 1]}` if (!fs.existsSync(fileName)) { await download(player.avatar, groupName) } // 下载后的本地的资源路径 player.localAvatar = fileName } } } // 需要多个文件合一 const sections = groupNames.map(groupName => { const info = data[groupName] const { institution, leader, phone, coach, doctor, players } = info // 标头内容 // let headers = ["序号", "照片", "姓名", "性别", "出生年月", "体重", "级别", "备注"] let headers = ["序号", "照片", "姓名", "性别", "身份证号", "级别", "备注"] // 表格数据 let tableData: any[][] = [] tableData.push(headers) // 填充选手信息 let index = 1 for (let player of players) { tableData.push([ index.toString(), player.localAvatar || "", player.name, player.gender === Gender.Male ? "男" : "女", player.idCard, // player.birthday, // player.weight, player.level, player.remark, ]) index++ } // 表格渲染 const tableRows = tableData.map(colums => { return new TableRow({ children: colums.map(cell => { return new TableCell({ verticalAlign: VerticalAlign.CENTER, width: { // 设置宽度 dxa长度单位 https://stackoverflow.com/questions/14360183/default-wordml-unit-measurement-pixel-or-point-or-inches size: longHeaders.some(j => cell === j) ? 3000 : 800, type: WidthType.DXA, }, children: cell && colums.findIndex(i => i === cell) === 1 && cell !== "照片" ? [new Paragraph({ alignment: AlignmentType.CENTER, children: [ new ImageRun({ // 将图片转化为buffer data: fs.readFileSync(cell), transformation: { width: 100, height: 129, }, }) ] })]: [new Paragraph({ alignment: AlignmentType.CENTER, children:[ new TextRun(cell || "") ] })] }) }) }) }) // 渲染报名表格 const table = new Table({ alignment: AlignmentType.CENTER, rows: tableRows }) return { properties: {}, children: [ // new Paragraph({ // style: "wellSpaced", // children: [ // new TextRun({ // text: "附件 4", // color: "999999", // }) // ], // }), // 表头信息 new Paragraph({ spacing: { before: 400, after: 400 }, style: "Title", text: `自 由 搏 击 比 赛 报 名 表(${groupName === Gender.Male ? "男子" : "女子"})`, heading: HeadingLevel.TITLE, alignment: AlignmentType.CENTER }), // 队伍信息 new Table({ style: "wellSpaced", alignment: AlignmentType.CENTER, borders: noBoder, rows: [ new TableRow({ children: [ new TableCell({ width: { size: 600, type: WidthType.DXA, }, borders: noBoder, children: [ new Paragraph(`单位: `), ], }), new TableCell({ width: { size: 1800, type: WidthType.DXA, }, borders: noBoder, children: [ new Paragraph(`${institution}`) ], }), new TableCell({ width: { size: 700, type: WidthType.DXA, }, borders: noBoder, children: [ new Paragraph(` 领队: `), ], }), new TableCell({ width: { size: 1200, type: WidthType.DXA, }, borders: noBoder, children: [ new Paragraph(`${leader}`) ], }), new TableCell({ width: { size: 1100, type: WidthType.DXA, }, borders: noBoder, children: [ new Paragraph(` 联系电话: `), ], }), new TableCell({ width: { size: 1400, type: WidthType.DXA, }, borders: noBoder, children: [ new Paragraph(`${phone}`) ], }), new TableCell({ width: { size: 700, type: WidthType.DXA, }, borders: noBoder, children: [ new Paragraph(` 教练: `), ], }), new TableCell({ width: { size: 1300, type: WidthType.DXA, }, borders: noBoder, children: [ new Paragraph(`${coach}`) ], }), new TableCell({ width: { size: 700, type: WidthType.DXA, }, borders: noBoder, children: [ new Paragraph(` 队医: `), ], }), new TableCell({ width: { size: 1300, type: WidthType.DXA, }, borders: noBoder, children: [ new Paragraph(`${doctor}`) ], }), ], }), ] }), // 用于段落距离(table无法设置spacing属性) new Paragraph({ spacing: { // 通过调整before值来调整段落渐进 before: 400, }, text: ``, }), // 选手信息 table, // 印章和时间 new Paragraph({ style: "wellSpaced", children: [ new TextRun({ text: "\t\t\t\t报名单位章:\t\t\t\t\t\t", }), new TextRun({ text: "年\t\t" }), new TextRun({ text: "月\t\t" }), new TextRun({ text: "日" }) ] }) ] } }) // 创建整个文档 const doc = new Document({ styles: { paragraphStyles: [ { id: "Title", name: "title", basedOn: "Normal", next: "Normal", quickFormat: true, run: { size: 30, bold: true, color: "000000" } }, { id: "wellSpaced", name: "Well Spaced", basedOn: "Normal", quickFormat: true, paragraph: { indent: { left: convertInchesToTwip(0.5), }, spacing: { before: 400, }, }, }, ], }, sections }) // 生成word文档 Packer.toBuffer(doc).then((buffer) => { fs.writeFileSync("enrolls.docx", buffer) }) // 删除下载的选手照片 delStaticFile(groupNames)}const group: GroupSchema = { institution: "江苏省南京市舜禹集团总部", leader: "王猛(男)", phone: "18861856665", coach: "刘国梁(男)", doctor: "杨永信(女)", players: [ { name: "莱昂纳多迪卡普里奥", gender: Gender.Male, idCard: "320888199001019878", birthday: "1999-01-02", weight: "60kg", avatar: "https://multi-xm.oss-cn-hangzhou.aliyuncs.com/atms/13.png", remark: "", level: "60kg" }, { name: "张三", gender: Gender.Male, idCard: "320888199001019878", birthday: "1999-01-02", weight: "60kg", avatar: "https://multi-xm.oss-cn-hangzhou.aliyuncs.com/atms/7.png", remark: "", level: "60kg" }, { name: "张三", gender: Gender.Male, idCard: "320888199001019878", birthday: "1999-01-02", weight: "60kg", avatar: "https://multi-xm.oss-cn-hangzhou.aliyuncs.com/atms/14.png", remark: "", level: "60kg" }, { name: "张三", gender: Gender.Male, idCard: "320888199001019878", birthday: "1999-01-02", weight: "60kg", avatar: "https://multi-xm.oss-cn-hangzhou.aliyuncs.com/atms/14.png", remark: "", level: "60kg" }, { name: "张三", gender: Gender.Male, idCard: "320888199001019878", birthday: "1999-01-02", weight: "60kg", avatar: "https://multi-xm.oss-cn-hangzhou.aliyuncs.com/atms/14.png", remark: "", level: "60kg" }, { name: "张三", gender: Gender.Male, idCard: "320888199001019878", birthday: "1999-01-02", weight: "60kg", avatar: "https://multi-xm.oss-cn-hangzhou.aliyuncs.com/atms/14.png", remark: "", level: "60kg" }, { name: "张三", gender: Gender.Male, idCard: "320888199001019878", birthday: "1999-01-02", weight: "60kg", avatar: "https://multi-xm.oss-cn-hangzhou.aliyuncs.com/atms/14.png", remark: "", level: "60kg" }, { name: "张三", gender: Gender.Male, idCard: "320888199001019878", birthday: "1999-01-02", weight: "60kg", avatar: "https://multi-xm.oss-cn-hangzhou.aliyuncs.com/atms/14.png", remark: "", level: "60kg" }, { name: "张三", gender: Gender.Male, birthday: "1999-01-02", weight: "60kg", avatar: "https://multi-xm.oss-cn-hangzhou.aliyuncs.com/atms/14.png", idCard: "320888199001019878", remark: "", level: "60kg" }, { name: "张三", gender: Gender.Male, idCard: "320888199001019878", birthday: "1999-01-02", weight: "60kg", avatar: "https://multi-xm.oss-cn-hangzhou.aliyuncs.com/atms/14.png", remark: "", level: "60kg" }, { name: "张三", gender: Gender.Male, idCard: "320888199001019878", birthday: "1999-01-02", weight: "60kg", avatar: "https://multi-xm.oss-cn-hangzhou.aliyuncs.com/atms/14.png", remark: "", level: "60kg" }, { name: "张三", gender: Gender.Male, idCard: "320888199001019878", birthday: "1999-01-02", weight: "60kg", avatar: "https://multi-xm.oss-cn-hangzhou.aliyuncs.com/atms/14.png", remark: "", level: "60kg" } ]}const data: DataSchema = { [Gender.Male]: group, [Gender.Female]: group,}generate(data)
更多node相关知识,请访问:nodejs 教程!
以上就是怎么利用node生成word文档?使用库分享的详细内容,更多请关注php中文网其它相关文章!