欢迎光临
我们一直在努力

怎么利用node生成word文档?使用库分享

怎么利用node生成word文档?下面本篇文章给大家介绍一下使用node生成word文档的方法,分享一个实用库,聊聊该库的使用方法,希望对大家有所帮助!

最近有项目需要用到生成word文档,平时经常用的都是通过模板生成,里面变量使用占位符替换,好处是快捷、方便、简单、不需要通过代码调word样式,确定是很多库不支持图片绘制(很多都是付费功能),找一圈,发现一个很有意思的库,正好也满足我们的需求,特此分享一下

依赖

// https://docx.js.org/#/ npm i docx   // https://www.npmjs.com/package/download npm 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)     }   } }  // 生成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: 'tttt报名单位章:tttttt',             }),             new TextRun({               text: '年tt'             }),             new TextRun({               text: '月tt'             }),             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)

赞(0)
【声明】:本博客不参与任何交易,也非中介,仅记录个人感兴趣的主机测评结果和优惠活动,内容均不作直接、间接、法定、约定的保证。访问本博客请务必遵守有关互联网的相关法律、规定与规则。一旦您访问本博客,即表示您已经知晓并接受了此声明通告。