How to use node to generate word documents? Share using libraries
How to use node to generate word documents? The following article will introduce to you how to use node to generate word documents, share a practical library, and talk about how to use the library. I hope it will be helpful to everyone!
Recently, there is a project that needs to generate word documents. Usually, they are generated through templates. The variables inside are replaced with placeholders. The advantage is that it is fast, convenient and simple. , there is no need to adjust the word style through code. It is sure that many libraries do not support image drawing (many of them are paid functions). After searching around, I found a very interesting library that just meets our needs. I would like to share it
Dependency
// https://docx.js.org/#/ npm i docx // https://www.npmjs.com/package/download npm i download
Instructions, because docx drawing only supports file streams, so network files must be downloaded locally and converted into buffer
Code
Without further ado, here’s the code
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) } } } // 生成word async 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)
For more node-related knowledge, please visit: nodejs tutorial!
The above is the detailed content of How to use node to generate word documents? Share using libraries. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics



This article will give you an in-depth understanding of the memory and garbage collector (GC) of the NodeJS V8 engine. I hope it will be helpful to you!

The Node service built based on non-blocking and event-driven has the advantage of low memory consumption and is very suitable for handling massive network requests. Under the premise of massive requests, issues related to "memory control" need to be considered. 1. V8’s garbage collection mechanism and memory limitations Js is controlled by the garbage collection machine

How to handle file upload? The following article will introduce to you how to use express to handle file uploads in the node project. I hope it will be helpful to you!

The file module is an encapsulation of underlying file operations, such as file reading/writing/opening/closing/delete adding, etc. The biggest feature of the file module is that all methods provide two versions of **synchronous** and **asynchronous**, with Methods with the sync suffix are all synchronization methods, and those without are all heterogeneous methods.

This article will share with you Node's process management tool "pm2", and talk about why pm2 is needed, how to install and use pm2, I hope it will be helpful to everyone!

Detailed explanation and installation guide for PiNetwork nodes This article will introduce the PiNetwork ecosystem in detail - Pi nodes, a key role in the PiNetwork ecosystem, and provide complete steps for installation and configuration. After the launch of the PiNetwork blockchain test network, Pi nodes have become an important part of many pioneers actively participating in the testing, preparing for the upcoming main network release. If you don’t know PiNetwork yet, please refer to what is Picoin? What is the price for listing? Pi usage, mining and security analysis. What is PiNetwork? The PiNetwork project started in 2019 and owns its exclusive cryptocurrency Pi Coin. The project aims to create a one that everyone can participate

The event loop is a fundamental part of Node.js and enables asynchronous programming by ensuring that the main thread is not blocked. Understanding the event loop is crucial to building efficient applications. The following article will give you an in-depth understanding of the event loop in Node. I hope it will be helpful to you!

The reason why node cannot use the npm command is because the environment variables are not configured correctly. The solution is: 1. Open "System Properties"; 2. Find "Environment Variables" -> "System Variables", and then edit the environment variables; 3. Find the location of nodejs folder; 4. Click "OK".
