位置: IT常识 - 正文

【实战分享】js生成word(docx),以及将word转成pdf解决方案分享(js技术干货分享)

编辑:rootadmin
【实战分享】js生成word(docx),以及将word转成pdf解决方案分享

推荐整理分享【实战分享】js生成word(docx),以及将word转成pdf解决方案分享(js技术干货分享),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:js 教程视频,js技巧,js教程免费视频,js入门视频,js技巧,js玩法,js技巧,js技巧,内容如对您有帮助,希望把文章链接给更多的朋友!

本文将记录如何用js生成word文件,并在node服务器端将word转换成pdf。记录的代码均是在真实业务场景中使用成功的代码,没有记录中间踩坑的过程。想直接抄答案的家人们可以跳转到1.2 程序编写部分,最终效果图可在1.2 程序编写部分中4. 效果展示模块查看。

如果有更好的解决方案,也欢迎大家在评论区讨论、分享~

本文demo存放地址:github.com/ChicKo1108/…

一、DocxTemplater:使用js生成word

老铁们,话不多说,先上链接:Docxtemplater | Word, Powerpoint, Excel generation using templates in your application | docxtemplater

DocxTemplater是一个基于模板生成最终文件的插件,它通过一个简单的{tag}语法将预设的数据填入模板Word或者Powerpoint中,帮助开发者快速生成最终文件。

由于DocxTemplater是基于{tag}变量替换,得到最终的文件,因此文件的样式是非常可控的。在开发过程中,设计师只需要出一版最终的成品word,开发者将内容替换成对应的{tag}即可(再也不用被设计师追着还原设计稿了!)。

DocxTemplater是一个收费的库,但是它拥有免费的开源版本,对于我所涉及的业务,使用免费版本完全可以解决。

开源版包括的功能包括:

{tag}替换条件判断循环图片渲染

除免费版外,它还拥有pro plan(950€ per\year)、Entreprise plan(24500€ per\year),具体功能大家可以前往官网查看。(但是白嫖的永远是最香的!)

由于我的业务只涉及生成word和pdf,所以本文只介绍word的相关内容,如果需要处理ppt,大家可前往官网自行学习。

1.1 模板语法

在了解模板语法之前,我们需要先创建一个tempalte.docx模板文件。

变量替换

变量使用{key}标签,在tempalte.docx文件中输入以下模板:

Hello, my name is {name}.

然后准备以下数据:

let data = { name: "千万",}

最终我们生成的docx文件将会是:

Hello, my name is 千万.条件判断

条件判断使用{#key}开始,使用{/key}结束,最简单的用法是使用Boolean类型数据进行填充。

Hello, my name is {name}.{#hasAge}I'm {age} years old.{/hasAge}{#hasWeight}My weight is {weight}.{/hasWeight}

然后准备以下数据:

let data = { name: "千万", hasAge: true, age: 23, hasWeight: false,}

最终我们生成的docx文件将会是:

Hello, my name is 千万.I'm 23 years old.

除了Boolean类型的数据以外,我们也可以填充其他类型:

type是否显示模块false / 空数组不显示非空数组显示,且将循环渲染内部元素对象显示,且使用对象内部变量替换{tag}其他真值显示

如果变量填充了数组,其实就是我们下面要介绍的循环语法,在下面一小节中再进行介绍。

在这里简单说一下填充对象的情况:

准备word模板如下:

总价格:{price}{#product} ${productName}: ${price} {/product}

准备数据如下:

let data = { price: 159, product: { productName: 'pencel', price: 1.2 }}

最终我们生成的docx文件将会是:

总价格:159pencel:$1.2 循环

循环的标志与条件判断相同,但对应的变量应使用Array来填充。

{#examScoreList} {exam}: {score}{/examScoreList} 【实战分享】js生成word(docx),以及将word转成pdf解决方案分享(js技术干货分享)

然后我们填充以下数据:

let data = { examScoreList: [ { exam: 数学, score: 60 }, { exam: 语文, score: 50 }, { exam: 英语, score: 40 }, ],}

最终我们生成的docx文件将会是:

数学: 60 语文: 50 英语: 40 表格循环

值得注意的是,循环不仅仅可以循环一段普通文字,我们也可以对表格进行循环,包括:循环行和循环整个表。如果想要循环渲染多个表格,只需要在表格外面使用循环语法即可,不在此处过多赘述。下面展示循环渲染一个表中的行的写法:

上图中可以看到,我在表格的第二行中使用了循环语法进行填写,这样我们最终生成的文档中,表头和尾就不会被循环,第二行将会被多次渲染,结果如下:

图片

图片使用{%image}进行标注即可,对于图片的数据传入需要特殊处理,后面的部分会进行介绍。

总结

根据以上语法,我们就可以准备对应的word模板文件了,大部分场景下应该都可以满足。在准备模板的时候,固定的文案和样式直接保留在文档中即可,包括页眉、页脚,各个段落的行距、间距,文字的字体、大小等。其他需要根据真实数据渲染的值,就用标签标注上。准备好模板文件以后,就可以开始脚本函数的编写了。

PS: 要善用表格进行排版布局!

1.2 程序编写安装所需库npm install docxtemplaternpm install docxtemplater-image-module-free // 图片模块,没有图片需求可以不装npm install pizzip // 处理模板文件用到,且只能使用该库 客户端生成1. 获取模板文件的binaryStringfunction getFileBinaryString(templateFile) { // templateFile是File对象 return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = (e) => { resolve(e.target.result); } reader.onerror = reject; reader.readAsBinaryString(templateFile); });}

这里使用到了FileReader类,用于将模板文件转换为binaryString,需要注意浏览器的兼容性。

如果对兼容性有要求,可以是使用pizzip/utils中提供的方法getBinaryContent,但是此库对ts兼容性比较差,因此我在实际代码中使用了FileReader。

import PizZipUtils from "pizzip/utils/index.js";function loadFile(url, callback) { PizZipUtils.getBinaryContent(url, callback); } 2. 生成最终文件(无需图片)// generate-doxc.jsimport PizZip from 'pizzip';import DocxTemplater from 'docxtemplater';function getFileBinaryString(templateFile) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = (e) => { resolve(e.target.result); } reader.onerror = reject; reader.readAsBinaryString(templateFile); });}export async function generateDocxFile(template, fileData) { return new Promise((resolve, reject) => { getFileBinaryString(template) .then(templateData => { const zip = new PizZip(templateData); const doc = new DocxTemplater() .loadZip(zip) .render(fileData); // fileData是我们需要定义好,传给docxtempale的数据。 const out = doc.getZip().generate({ type: 'blob', mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', }); resolve(out); }) .catch(reject); });} 3. 准备数据,生成最终文件

接下来我们准备一个<input type="file" />的文件输入框(你也可以使用网络请求,或者任何方式拿到文件,只要最终获得二进制数据就可以),用来获取模板文件。同时准备好相应的数据,来对模板进行填充。

// App.jsximport { saveAs } from 'file-saver';import { generateDocxFile } from './utils/generate-docx';const fileData = { intro: '国际劳动节,又称五一国际劳动节、劳动节、国际示威游行日,是纪念工人和劳工运动的斗争和成果的日子。国际劳动节是一项由国际劳工运动所推动的节日,全世界劳工和工人阶级在一般会在五朔节(5月1日)举行的庆祝节日,而美国和加拿大在9月第一个星期一举行。是世界上80多个国家的劳动节。', activities: [ { name: '阿尔及利亚', activity: '在阿尔及利亚,5月1日是公共假日,以庆祝劳动节。' }, { name: '安哥拉', activity: '5月1日在安哥拉被承认为公共假日,称为劳动节。' }, { name: '埃及', activity: '在埃及,5月1日被称为劳动节,是一个带薪的公共假期。在传统上,埃及总统会主持正式的五一节庆祝活动。' }, { name: '加纳', activity: '5月1日是加纳的一个节日,属于庆祝全国所有工人。工会和劳工协会以游行的形式来庆祝劳动节。加纳也会举行阅兵式,通常由工会大会秘书长和各地区的区域秘书致辞。来自不同工作地点的工人通过条幅和衣着表明他们的公司。' } ]}function App() { const handleFileChange = async (e) => { const file = e.target.files[0]; const out = await generateDocxFile(file, fileData); saveAs(out, `${new Date().getTime()}.docx`); } return ( <div className="App"> <input type="file" onChange={handleFileChange} /> </div> )}export default App; 4. 效果展示

模板文件如下:

生成结果如下:

5. 图片处理

如果需要在模板中使用图片,我们需要安装docxtemplater-image-module-free模块。

引入了此模块后,需要在加载模板文件后,载入image模块,然后异步填入数据。

// generate-docx.js// 将图片处理为base64,给模板使用function convertImgToBase64(url, outputFormat) { return new Promise((resolve, reject) => { let canvas = document.createElement( 'CANVAS', ); const ctx = canvas.getContext('2d'), img = new Image(); img.crossOrigin = 'Anonymous'; img.onload = function () { canvas.height = img.height; canvas.width = img.width; ctx.drawImage(img, 0, 0); var dataURL = canvas.toDataURL(outputFormat || 'image/png'); canvas = null; resolve(dataURL); }; img.onerror = function (e) { reject(e); }; img.src = url; });}const imageOpts = { // 图片的配置 centered: false, getImage: function (tagValue, tagName) { // 将图片转成base64 return new Promise((resolve) => { if (typeof tagValue === 'string' && base64Regex.test(tagValue)) { return resolve(tagValue); } else { convertImgToBase64(tagValue).then((base64) => { return resolve(base64Parser(base64)); }); } }); }, // 设置图片宽高,可以根据tagName为每一张图片设置不同宽高 getSize: function (img, tagValue, tagName) { // img是图片Buffer,tagValue是图片初始值,tagName是图片在模板中定义的标签key值 return [150, 150]; // [宽, 高] }};export async function generateDocxFile(template, fileData) { return new Promise((resolve, reject) => { getFileBinaryString(template) .then(templateData => { const zip = new PizZip(templateData); const doc = new DocxTemplater() .loadZip(zip) .attachModule(new ImageModule(imageOpts)) // 载入模块 .compile(); // 异步填充数据 doc.resolveData(fileData) .then(() => { doc.render(); const out = doc.getZip().generate({ type: 'blob', mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', }); docxLists.push({ file: out, fileName }); resolve(); }); }) .catch(reject); });}

对于有图片的文档生成,需要异步载入数据,且图片数据需要处理为base64,上述代码给出了处理图片的一种解决方案,如果大家有更高效的方法也可以自行使用。

node服务器端生成

该库同样支持在node中使用,其思想与在浏览器端基本一致,在node端可以直接使用buffer,下面贴出官方给出的代码示例。

const PizZip = require("pizzip");const Docxtemplater = require("docxtemplater"); const fs = require("fs");const path = require("path"); // Load the docx file as binary contentconst content = fs.readFileSync( path.resolve(__dirname, "input.docx"), "binary" );const zip = new PizZip(content);const doc = new Docxtemplater(zip,{ paragraphLoop: true, linebreaks: true,}); // Render the document (Replace {first_name} by John, {last_name} by Doe, ...)doc.render({ first_name: "John", last_name: "Doe", phone: "0652455478", description: "New Website",});const buf = doc.getZip().generate({ type: "nodebuffer", // compression: DEFLATE adds a compression step. // For a 50MB output document, expect 500ms additional CPU time compression: "DEFLATE",});// buf is a nodejs Buffer, you can either write it to a file or res.send it with express for example.fs.writeFileSync(path.resolve(__dirname, "output.docx"), buf); 1.3 总结

docxTemplater是一个通过模板文件生成word的库,它能最大程度的保证最终生成的word的样式的完整和还原。代码搭建好后,对于类似的业务,开发者们只需要编写更多的模板文件,并且把精力集中在对数据的处理上即可。

配合e-charts或其他图表库,也可以让我们实现报表文件的生成。

此外,对于pizzip这个库,它本身是对jszip库的一个升级,拥有对zip文件的操作能力,可以直接解压或者生成zip包,我们可以直接通过此库对批量生成的文件进行打包处理,打包主要用的api如下:

const zip = new pizZip();zip.file(fileName, fileBuffer); // 生成的文件名 以及 文件的 arrayBufferzip.generate({ type: 'blob' }), `documents.zip`); // 生成zip文件 二、使用libre office将word转换成pdf

在进行此部分业务时,原本想在前端把所有的工作都做好,但是没有找到在客户端就直接转换的方法。因此,此部分在服务器端进行解决。

首先需要在机器上安装libre office软件,具体方法可以自行搜索。

安装好后,项目中安装libreoffice-convert库,这个库对libre office的转换方法进行了封装,直接调用其中方法就好:

const path = require('path');const fs = require('fs');const libre = require('libreoffice-convert');async function docx2pdf(docxBuf, outputPath) { libre.convert(docxBuf, '.pdf', undefined, (err, outputBuf) => { if (err) { console.log(`Error converting file: ${err}`); } fs.writeFileSync(outputPath, outputBuf); });}const inputBuf = fs.readFileSync(path.join(__dirname, 'sample.docx'));let outputPath = path.join(__dirname, 'sample.pdf');docx2pdf(inputBuf, outputPath);

如果是zip文件,同样可以安装jsZip或者pizZip进行解压、打包等处理。这里更推荐使用jsZip,因为文档更加丰富,且对ts支持更好。

三、结束语

这是我第二次遇到此类业务,所以本着学习、记录、分享的心态,将内容分享到平台上。在开发过程中遇到了很多“坑”,并没有在本文中记录。本文主要还是以记录最终成功的代码为主,把内容分享给其他有同样需求的家人们。毕竟轮子已经这么完善了,当然要好好利用啦!

本文链接地址:https://www.jiuchutong.com/zhishi/285141.html 转载请保留说明!

上一篇:东内格罗斯省沿海的鹦嘴鱼,菲律宾 (© Tim Fitzharris/Minden Pictures)(内格罗斯岛)

下一篇:最小的单电相机是什么(最小巧的单反相机)

  • 又一母婴电商玩起“严选模式”,消费降级真的来了吗?(母婴带货网红)

    又一母婴电商玩起“严选模式”,消费降级真的来了吗?(母婴带货网红)

  • 平板如何设置儿童模式(我想给平板设置)

    平板如何设置儿童模式(我想给平板设置)

  • 苹果怎么设置四位数的锁屏密码(苹果怎么设置四个密码锁)

    苹果怎么设置四位数的锁屏密码(苹果怎么设置四个密码锁)

  • 荣耀手机如何设置导航三键(荣耀手机如何设置图标大小)

    荣耀手机如何设置导航三键(荣耀手机如何设置图标大小)

  • 荣耀30手机卡槽的打开方法(荣耀30手机卡槽位置)

    荣耀30手机卡槽的打开方法(荣耀30手机卡槽位置)

  • 抖音直播音浪怎么看不到(抖音直播音浪怎么赚钱)

    抖音直播音浪怎么看不到(抖音直播音浪怎么赚钱)

  • 加入黑名单和删除的区别电话(加入黑名单和删除联系人)

    加入黑名单和删除的区别电话(加入黑名单和删除联系人)

  • 怎么用身份证号查快手号(怎么用身份证号计算年龄公式excel)

    怎么用身份证号查快手号(怎么用身份证号计算年龄公式excel)

  • 京东临时账号怎么绑定成正式账号(京东临时账号怎么在app登陆)

    京东临时账号怎么绑定成正式账号(京东临时账号怎么在app登陆)

  • wps怎么打拼音带声调(wps中如何打拼音)

    wps怎么打拼音带声调(wps中如何打拼音)

  • rx560d相当于什么显卡(rx560d配什么处理器)

    rx560d相当于什么显卡(rx560d配什么处理器)

  • 华为权益版是什么意思(华为权益包有什么用)

    华为权益版是什么意思(华为权益包有什么用)

  • 华为荣耀10怎么分屏(华为荣耀10怎么样)

    华为荣耀10怎么分屏(华为荣耀10怎么样)

  • us sprint是什么版(us t-mobile / sprint (mvno))

    us sprint是什么版(us t-mobile / sprint (mvno))

  • 企鹅电竞黑屏怎么办(企鹅电竞怎么黑频不了)

    企鹅电竞黑屏怎么办(企鹅电竞怎么黑频不了)

  • 苹果耳机圆头扁头区别(苹果耳机扁头适用机型)

    苹果耳机圆头扁头区别(苹果耳机扁头适用机型)

  • 手机看视频卡顿怎么处理(手机看视频卡顿没声音怎么处理)

    手机看视频卡顿怎么处理(手机看视频卡顿没声音怎么处理)

  • 手机不读卡怎么回事(手机不读卡怎么办可以修吗)

    手机不读卡怎么回事(手机不读卡怎么办可以修吗)

  • 淘宝预售在哪里找(淘宝预售在哪里付尾款)

    淘宝预售在哪里找(淘宝预售在哪里付尾款)

  • oppoa9如何开关机(oppoa9手机怎么关机按哪里能关机)

    oppoa9如何开关机(oppoa9手机怎么关机按哪里能关机)

  • x27摄像头怎么出来(x27摄像头怎么出图像)

    x27摄像头怎么出来(x27摄像头怎么出图像)

  • 计算机的软件系统一般分为(计算机的软件系统主要包括)

    计算机的软件系统一般分为(计算机的软件系统主要包括)

  • 苹果airpods 2上市时间(苹果airpods2发售时间)

    苹果airpods 2上市时间(苹果airpods2发售时间)

  • 手机关机怎么定位(手机关机怎么定位位置)

    手机关机怎么定位(手机关机怎么定位位置)

  • 快手可以屏蔽别人吗(快手可以屏蔽别人的作品吗)

    快手可以屏蔽别人吗(快手可以屏蔽别人的作品吗)

  • 腾讯文件删除的文件怎么恢复(腾讯文件删除的图片怎么恢复)

    腾讯文件删除的文件怎么恢复(腾讯文件删除的图片怎么恢复)

  • vue3 子组件上绑定(v-model=“xx“) 父组件传过来的值后报错(vue 绑定子组件属性)

    vue3 子组件上绑定(v-model=“xx“) 父组件传过来的值后报错(vue 绑定子组件属性)

  • pushd命令  添加目录到目录堆栈顶部(push添加对象)

    pushd命令 添加目录到目录堆栈顶部(push添加对象)

  • 个体户定期定额征收标准
  • 购买需要安装的设备会计分录
  • 基本税种有哪些税种
  • 期末留抵税额是怎么产生的
  • 税收要素的灵魂
  • 生产成本明细科目是材料还是产品
  • 固定资产盘盈为什么计入盈余公积
  • 发票验旧期限
  • 小规模简易征收计算方法
  • 实收资本认缴怎么缴纳印花税
  • 房地产行业企业所得税政策
  • 软件企业享受税收优惠
  • 未支付商标使用费怎么办
  • 采购商品未入库的会计分录
  • 2018年城镇医保
  • 票据行为为什么没有付款
  • 企业购买扶贫物资怎么入账
  • 职工伙食团食谱
  • 开个人普发票需要什么资料?
  • 小规模纳税人代收水电费税率
  • 按期汇总缴纳印花税可以退税吗
  • 国税局预缴税款在哪里看
  • 过路费增值税可以抵扣吗
  • 应纳税所得额未减上季度所得税,下季度可补减吗
  • 为什么路由器经常断网
  • 在win7中如何找到WAN服务
  • 土地增值税清算收入如何确定
  • 什么情形不属于经警告无效人民警察可以使用武器的情形
  • 工程审计的目的包括哪些
  • 保险中介市场现状和基本特点
  • 公司中奖要交税吗
  • 人民币账户购汇支付
  • 珀泽申群岛上的阿德利企鹅,南极洲 (© Tui De Roy/Minden Pictures)
  • unet网络的优缺点
  • php调用其他php函数
  • php时间戳转换成时间
  • 小规模负数发票怎么申报增值税
  • labview实例教程
  • while循环语法结构
  • 小规模纳税人核定征收标准
  • 普票退货需要开红字信息表吗
  • 小微企业的所得税税率是多少
  • 融资租赁手续费一次性还是摊销
  • 中间人拿回扣是什么行为
  • mysql中如何设置默认值
  • 收到捐赠的账务处理和涉税处理
  • 期末留抵的进项税可以计入成本吗
  • 出让价格不得低于基准地价
  • 房屋租赁费可以抵扣吗
  • 小规模纳税人开专票税率是多少?
  • 如何做好现金流
  • 结账时应当结出每个账户的期末余额对吗
  • centos7.4
  • win7 32位旗舰版电脑城下载
  • win8/10whql
  • solaris 11.3
  • win8命令提示符管理员怎么打开
  • win7电脑开机提示oxcoooooe9
  • 如何使用ssh
  • win7防火墙在哪设置
  • linux中如何修改文件内容
  • 安卓应用程序数据
  • Android中的touch事件
  • perl怎么用
  • node mongoose
  • bat文件加密如何解锁
  • node.js redis
  • python3 django教程
  • android点击事件onclick用法
  • js图片轮播和点击切换
  • 电子原理图实例讲解
  • 安卓手机管家删除的照片怎么恢复
  • python utils模块
  • js缩小图片尺寸
  • 美股印花税如何收取
  • 新疆国税网上营业厅
  • 广西电子发票如何申请
  • 青岛税务局网上办税厅app
  • 四川职工医保联网了吗
  • 税务设备有什么特点
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设