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

广告:宝塔Linux面板高效运维的服务器管理软件 点击【 https://www.bt.cn/p/uNLv1L 】立即购买

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

怎么利用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文档?使用库分享的详细内容,更多请关注9543建站博客其它相关文章!

广告:SSL证书一年128.66元起,点击购买~~~

9543建站博客
一个专注于网站开发、微信开发的技术类纯净博客。

作者头像
admin创始人

肥猫,知名SEO博客站长,14年SEO经验。

上一篇:noframes标签是什么意思
下一篇:vue3如何使用el-upload上传文件

发表评论

关闭广告
关闭广告