Vue中前端导出word文件

很多时候在工作中会碰到完全由前端导出word文件的需求,因此特地记录一下比较常用的几种方式。

一、提供一个word模板

该方法提供一个word模板文件,数据通过参数替换的方式传入word文件中,灵活性较差,适用于简单的文件导出。需要依赖:docxtemplater、file-saver、jszip-utils、pizzip

在这里插入图片描述

javascript
复制代码
import Docxtemplater from "docxtemplater";
import { saveAs } from "file-saver";
import JSZipUtils from "jszip-utils";
import PizZip from "pizzip";export function downloadWithTemplate(path, data, fileName) {JSZipUtils.getBinaryContent(path, (error, content) => {if (error) throw error;const zip = new PizZip(content);const doc = new Docxtemplater().loadZip(zip);doc.setData({...data.form,// 循环项参数list: data.list,outsideList: data.outsideList,});try {doc.render();} catch (error) {const e = {message: error.message,name: error.name,stack: error.stack,properties: error.properties,};ElMessage.error("文件格式有误!");throw error;}const out = doc.getZip().generate({type: "blob",mimeType:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",});saveAs(out, fileName);});
}let data = {form: {title: "这是word标题",test: "这是表单1的数据",test1: "111",test2: 222,test3: 333,},outsideList: [{list: [{index: 0,table: "表格第一项",table1: "表格第二项",table2: "表格第三项",},{index: 1,table: "表格第一项",table1: "表格第二项",table2: "表格第三项",},],},{list: [{index: 0,table: "表格第一项",table1: "表格第二项",table2: "表格第三项",},{index: 1,table: "表格第一项",table1: "表格第二项",table2: "表格第三项",},],},],};downloadWithTemplate("template.docx", data, "模板word.docx")

调用downloadWithTemplate方法即可导出如下文件: 在这里插入图片描述
注: 上述方法中的path参数为你在vue项目中存放公共文件的位置,在vue2中为static文件夹下,在vue3中为public文件夹下。

二、根据html代码转换为word文件(推荐)

顾名思义,这个方法就是将我们在页面上书写的html代码直接转换成word文件,这也是我最推荐的一种方法,因为大部分的样式可控,且毕竟是我们较为熟悉的方式。需要插件: html-docx-js-typescript、file-saver。

xml
复制代码
import { saveAs } from "file-saver";
import { asBlob } from "html-docx-js-typescript";export function downloadWordWithHtmlString(html, name) {let htmlString = `<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Document</title></head><body>${html}</body></html>`;asBlob(htmlString).then((data) => {saveAs(data, `${name}.docx`);});
}`

使用案例:

ini
复制代码
<div ref="word"><h3 style="text-align: center">word标题</h3><tableborder="1"cellspacing="0"width="600"style="font-size: 12px; color: #000; text-align: center"><tr height="50"><td width="100">1111</td><td widt="200" colspan="2">合并单元格</td><td width="300">最长的一项</td></tr><tr height="100"><td width="100">222</td><td width="100">222</td><td width="100">222</td><td width="100">222</td></tr></table><table width="600" border="1" cellspacing="0"><tr height="50"><td width="100">1111</td><td rowspan="3">合并包括此行在内的下面三行</td></tr><tr height="100"><td>222</td></tr><tr height="300"><td>3333</td></tr><tr><td>50</td></tr></table>
</div>let word = ref(null);
downloadWordWithHtmlString(word.value.innerHTML, 'html字符串word.docx');

生成的word文件可以看到效果和在网页中的html代码一样:

在这里插入图片描述
另外需要注意的是,若是需要在word中添加分页符,在需要分页的内容处添加CSS属性page-break-before即可。此时在浏览器上打印出innerHTML值会发现:

在这里插入图片描述

mdn上介绍page-break-before属性已经被break-before属性替代,但是经过我实际测试发现当html字符串是page-break: always时生成的word文件没有分页效果,反而是将其替换回page-break-before后实现了分页效果。若有大神知道这是什么问题还望不吝赐教。 因此需要在downloadWordWithHtmlString方法中添加一句正则: htmlString = htmlString.replace( /break-(after|before): page/g, "page-break-$1: always;" );,此时就能实现分页效果。

三、使用docx插件

第二种方法有个很致命的问题就是它无法在生成的word文件中添加图片页眉,我搜遍了npm也只找到一个能添加文字页眉的插件: html-docx-ts要想实现这个需求,就需要用到docx插件。 docx官网的介绍是"Easily generate and modify .docx files with JS/TS. Works for Node and on the Browser.",意味着是一个专门用于生成word和修改word的文件。该插件就需要一个一个去配置你要生成的项,然后组合成一个word。一个简单的案例是:

css
复制代码
import {Document,Paragraph,Header,TextRun,Table,TableRow,TableCell,WidthType,Packer,
} from "docx";
import { saveAs } from "file-saver";const document = new Document({sections: [{headers: {default: new Header({children: [new Paragraph("我是页眉")],}),},children: [new Paragraph({children: [new TextRun({text: "我是文字内容",size: 16,bold: true,}),],}),new Table({columnWidths: [1500, 7500],rows: [new TableRow({children: [new TableCell({width: {size: 1500,type: WidthType.DXA,},children: [new Paragraph({alignment: "center",children: [new TextRun({text: "测试",size: 24,font: {name: "楷体",},}),],}),],}),],}),],}),],},],});Packer.toBlob(document).then((blob) => {saveAs(blob, "test.docx");});

导出的word文件形式为:

在这里插入图片描述
下面是我个人总结的比较常见能用到的功能和配置项:

css
复制代码
// 导出文字
1.new Paragraph(text) -> 默认字体样式: 宋体,五号字
2.new Paragraph({children: [new TextRun({text: "我是文字内容",size: 16, // 对应word中的字体大小8bold: true, // 是否加粗underline: {type: UnderlineType.SINGLE,color: "#2e32ee",}, // 下划线类型及颜色font: {name: "仿宋", // 只要是word中有的字体类型都可以生效},}),],indent: {left: 100,}, // 离左边距离 类似于margin-leftspacing: {before: 150,after: 200,}, // 离上边和下边的距离 类似于margin-top/bottomalignment: "center", // 对齐方式pageBreakBefore: true, // 是否在这段文字前加入分页符})// 导出表格
new Table({columnWidths: [1500, 7500], // 表示单行有几项,总宽度是9000,对应宽度;rows: [new TableRow({children: [new TableCell({width: {size: 1500, // 需与columnWidths的第一项对应type: WidthType.DXA, // 官网的介绍是Value is in twentieths of a point// 因为表格的总宽度是以twips(每英寸的1/20)为单位进行计算的},children: [new Paragraph({alignment: "center",children: [new TextRun({text: "测试",size: 24,font: {name: "楷体",},}),],}),],}),new TableCell({width: {size: 7500,type: WidthType.DXA,},children: [new Paragraph('ccc'),],margins: {top: 500,bottom: 500,left: 500} // 类似于单元格内容的padding}),],}),],
})// 导出图片
new Paragraph({children: [new ImageRun({data: "base64", // 图片需转成base64的形式transformation: {width: 100,height: 30,}, // 图片宽高}),],
})// 设置页眉页脚
headers: {default: new Header({children: [new Paragraph("我是页眉")],}),
},
footers: {default: new Footer({children: [new Paragraph("我是页脚")],}),
}

下面是一个完整的使用案例:

css
复制代码
const document = new Document({sections: [{headers: {default: new Header({children: [new Paragraph({children: [new ImageRun({data: "data:image/jpeg;base64,...",transformation: {width: 150,height: 150,},}),],}),],}),},footers: {default: new Footer({children: [new Paragraph("我是页脚")],}),},children: [new Paragraph("第一行直接默认形式"),new Paragraph({children: [new TextRun({text: "下一页",}),],pageBreakBefore: true,}),new Table({columnWidths: [1500, 7500],rows: [new TableRow({children: [new TableCell({width: {size: 1500,type: WidthType.DXA,},children: [new Paragraph({alignment: "center",children: [new TextRun({text: "测试",size: 24,font: {name: "楷体",},}),],}),],}),new TableCell({width: {size: 7500,type: WidthType.DXA,},children: [new Paragraph({children: [new ImageRun({data: "data:image/jpeg;base64,...",transformation: {width: 150,height: 150,},}),],}),],margins: {top: 500,bottom: 500,left: 500,},}),],}),],}),],},],
});Packer.toBlob(document).then((blob) => {saveAs(blob, "test.docx");
});

此时导出的word文件如下:

在这里插入图片描述
学习更多vue开发知识请下载​​CRMEB开源商城​​附件学习

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/90452.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

论文笔记(整理):轨迹相似度顶会论文中使用的数据集

0 汇总 数据类型数据名称数据处理出租车数据波尔图 原始数据&#xff1a;2013年7月到2014年6月&#xff0c;170万条数据 ICDE 2023 Contrastive Trajectory Similarity Learning with Dual-Feature Attention 过滤位于城市&#xff08;或国家&#xff09;区域之外的轨迹 过…

Idea引入thymeleaf失败解决方法

报错 Whitelabel Error Page This application has no explicit mapping for /error, so you are seeing this as a fallback.Fri Sep 29 09:42:00 CST 2023 There was an unexpected error (typeNot Found, status404). 原因&#xff1a;html没有使用thymeleaf 首先要引入…

Linux Day18 TCP_UDP协议及相关知识

一、网络基础概念 1.1 网络 网络是由若干结点和连接这些结点的链路组成&#xff0c;网络中的结点可以是计算机&#xff0c;交换机、 路由器等设备。 1.2 互联网 把多个网络连接起来就构成了互联网。目前最大的互联网就是因特网。 网络设备有&#xff1a;交换机、路由器、…

【MATLAB源码-第38期】基于OFDM的块状导频和梳状导频误码率性能对比,不同信道估计方法以及不同调制方式对比。

1、算法描述 块状导频和梳状导频都是用于无线通信系统中信道估计的方法。 块状导频&#xff1a; 定义&#xff1a; 在频域上&#xff0c;块状导频是连续放置的一组导频符号。这意味着所有的导频符号都集中在一个短的时间段内发送。 优点&#xff1a; 对于时间选择性信道&#…

Python 打印素数

"""打印素数介绍&#xff1a;素数是指只有两个正因数&#xff08;1和它本身&#xff09;的自然数&#xff0c;而且必须大于1。例如&#xff1a;2、3、5、7、11、13、17、19、23、29等等都是素数。小于2的数不是素数&#xff0c;因为它没有两个正因数。例如&…

基于JAVA+SpringBoot的新闻发布平台

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 随着科技的飞速发展和…

IO流 之 缓冲流(字节缓冲流和字符缓冲流)

缓冲流对原始流进行了包装&#xff0c;以提高原始流读写数据的性能。 字节缓冲流&#xff08;BufferedInputStream和BufferedOutputStream&#xff09; 字节缓冲流在内存中提供了一个默认为8kb的区域&#xff0c;用于缓冲&#xff0c;当流开始时&#xff0c;先读取一个8kb的内…

skywalking入门

参考&#xff1a; https://www.jianshu.com/p/ffa7ddcda4ab 参考&#xff1a; https://developer.aliyun.com/article/1201085 skywalking&#xff08;APM&#xff09; 调用链路分析以及应用监控分析工具 Skywalking主要由三大部分组成&#xff1a;agent、collector、webapp-…

十六.镜头知识之工业镜头的质量判断因素

十六.镜头知识之工业镜头的质量判断因素 文章目录 十六.镜头知识之工业镜头的质量判断因素1.分辨率(Resolution)2.明锐度(Acutance)3.景深(DOF)&#xff1a;4. 最大相对孔径与光圈系数5.工业镜头各参数间的相互影响关系5.1.焦距大小的影响情况5.2.光圈大小的影响情况5.3.像场中…

CISSP学习笔记:人员安全和风险管理概念

第二章 人员安全和风险管理概念 2.1 促进人员安全策略 职责分离: 把关键的、重要的和敏感工作任务分配给若干不同的管理员或高级执行者&#xff0c;防止共谋工作职责:最小特权原则岗位轮换:提供知识冗余&#xff0c;减少伪造、数据更改、偷窃、阴谋破坏和信息滥用的风险&…

快速幂矩阵-python

看了大神讲解&#xff0c;理论在这里&#xff1a;快速幂算法&#xff08;全网最详细地带你从零开始一步一步优化&#xff09;-CSDN博客 例题&#xff1a;求整数 base 的 整数 power 次方&#xff0c;对整数 num_mod 取幂。 python 代码如下&#xff1a; import timedef norm…

LabVIEW在运行时调整表控件列宽

LabVIEW在运行时调整表控件列宽 如何在LabIEW中运行时调整表控件的列宽大小&#xff1f; 在VI运行时&#xff0c;有两种不同的方法可以更改表中列的宽度。首先&#xff0c;可以使用鼠标手动更改它们;其次&#xff0c;可以从框图中以编程方式更改它们。 手动更改列宽 只有在…

IPsec_SSL VPN身份鉴别过程简要

一、IPsec VPN身份鉴别&#xff08;参考国密标准《GMT 0022-2014 IPsec VPN技术规范》&#xff09; IKE第一阶段&#xff08;主模式&#xff09; “消息2”由响应方发出&#xff0c;消息中具体包含一个SA载荷&#xff08;确认所接受的SA提议&#xff09;、响应方的签名证书和…

基于AI图像识别的智能缺陷检测系统,在钢铁行业的应用-技术方案

目录 概述 废钢智能检判方案简介 废钢智能检判系统优势及价值 废钢人工检判过程 废钢等级检判标准 废钢检判结果 智能检判方案-废钢智能检判算法 算法一&#xff1a;废钢等级识别算法 算法二&#xff1a;不合格料的位置识别算法 算法三&#xff1a;不合格料的类型识别…

【再识C进阶3(下)】详细地认识字符分类函数,字符转换函数和内存函数

前言 &#x1f493;作者简介&#xff1a; 加油&#xff0c;旭杏&#xff0c;目前大二&#xff0c;正在学习C&#xff0c;数据结构等&#x1f440; &#x1f493;作者主页&#xff1a;加油&#xff0c;旭杏的主页&#x1f440; ⏩本文收录在&#xff1a;再识C进阶的专栏&#x1…

全网最全面最精华的设计模式讲解,从程序员转变为工程师的第一步

前言 现代社会&#xff0c;技术日新月异&#xff0c;要想跟上技术的更新就必须不断学习&#xff0c;而学习技术最有效方式就是阅读优秀的源码&#xff0c;而优秀的源码都不是简单的逻辑堆积&#xff0c;而是有很灵活的设计模式应用其中&#xff0c;如果我们不懂设计模式&#…

idea2023根据表自动生成+springboot跑起来

idea安装插件 idea中显示数据库连接 就可以看到如下界面 选中你想生成的表&#xff0c;右键如下操作 如上就有了所有需要的后端代码 生成后&#xff0c;要查看一下mapper.xml中的文件是否 正确&#xff0c;若有误请先去修改&#xff0c;例如我的版本下生成了xml文件中缺乏…

基于SpringBoot的银行账目账户管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

51单片机用IIc控制OLED显示数组内容

为了能够看到51单片机接收到的串口数据&#xff0c;我选择了用oled显示收到的数据&#xff0c;特此花重金买了一块oled屏128X64的屏幕大概10来块钱吧&#xff01;首先要达成的小目标就是能够显示数组的内容&#xff0c;建立一个字符数组&#xff0c;用来接收串口收到的数据&…

基于SpringBoot的古典舞在线交流平台的设计与实现

目录 前言 一、技术栈 二、系统功能介绍 系统主界面 用户注册界面 论坛交流界面 课程详情界面 购物车界面 我的订单界面 管理员登录界面 会员用户管理界面 服饰管理界面 课程管理界面 三、核心代码 1、登录模块 2、文件上传模块 3、代码封装 前言 随着互联网技术…