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.rhkb.cn/news/141587.html

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

相关文章

28 WEB漏洞-XSS跨站之WAF绕过及安全修复

目录 常规WAF绕过思路标签语法替换特殊符号干扰提交方式更改垃圾数据溢出加密解密算法结合其他漏洞绕过 自动化工具说明强大的fuzzing引擎安全修复方案演示案例&#xff1a; 常规WAF绕过思路 标签语法替换 xss的效果可以由多个代码来实现&#xff0c;就类似于我们使用到的其它…

2023-9-25 排队打水

题目链接&#xff1a;排队打水 #include <iostream> #include <algorithm>using namespace std;typedef long long LL;const int N 100010;int n; int t[N];int main() {scanf("%d", &n);for(int i 0; i < n; i ) scanf("%d", &t…

【Java 基础篇】Executors工厂类详解

在多线程编程中&#xff0c;线程池是一项重要的工具&#xff0c;它可以有效地管理和控制线程的生命周期&#xff0c;提高程序的性能和可维护性。Java提供了java.util.concurrent包来支持线程池的创建和管理&#xff0c;而Executors工厂类是其中的一部分&#xff0c;它提供了一些…

基于UDP协议的网络服务器的模拟实现

目录 服务端类UdpServer的模拟实现 服务端类UdpServer的成员变量 服务端类UdpServer的构造函数、初始化函数initServer、析构函数 服务端类UdpServer的start函数 服务端类UdpServer的整体代码&#xff08;即udp_server.h文件的整体代码&#xff09; 基于服务端类UdpServe…

Tomcat中文路径目录

一、问题描述 linux环境下tomcat发布了包含中文名字的页面和文件&#xff0c;浏览器访问报404&#xff0c;非中文页面没有问题&#xff1b;本人为RP设计的原型图发布&#xff0c;其中包含了大量的中文文件和路径 二、解决步骤 第一步&#xff0c;设置tomcat&#xff0c;配置…

vue里使用elementui的级联选择器el-cascader进行懒加载的怎么实现数据回显?

需要实现的懒加载回显效果 比如&#xff1a;后端返回数据 广东省/广州市/天河区 &#xff1a;440000000000/440100000000/440106000000&#xff0c;需要我们自动展开到天河区的下一级&#xff0c;效果如下 代码实现 我的实现思路就是拿到 440000000000/440100000000/44010600…

Java版本企业工程项目管理系统平台源码(三控:进度组织、质量安全、预算资金成本、二平台:招采、设计管理)

工程项目管理软件&#xff08;工程项目管理系统&#xff09;对建设工程项目管理组织建设、项目策划决策、规划设计、施工建设到竣工交付、总结评估、运维运营&#xff0c;全过程、全方位的对项目进行综合管理 工程项目各模块及其功能点清单 一、系统管理 1、数据字典&#…

JavaScript 基础第三天笔记

JavaScript 基础第三天笔记 if 多分支语句和 switch的区别&#xff1a; 共同点 都能实现多分支选择&#xff0c; 多选1大部分情况下可以互换 区别&#xff1a; switch…case语句通常处理case为比较确定值的情况&#xff0c;而if…else…语句更加灵活&#xff0c;通常用于范围…

[每周一更]-(第64期):Dockerfile构造php定制化镜像

利用php官网镜像php:7.3-fpm&#xff0c;会存在部分插件缺失的情况&#xff0c;自行搭建可适用业务的镜像&#xff0c;才是真理 Dockerhub 上 PHP 官方基础镜像主要分为三个分支&#xff1a; cli: 没有开启 CGI 也就是说不能运行fpm。只可以运行命令行。fpm: 开启了CGI&#x…

PHP后台实现微信小程序登录

微信小程序官方给了十分详细的登陆时序图&#xff0c;当然为了安全着想&#xff0c;应该加上签名加密。 微信小程序端 1).调用wx.login获取 code 。 2).调用wx.getUserInfo获取签名所需的 rawData , signatrue , encryptData 。 3).发起请求将获取的数据发送的后台。 login: …

Spring学习笔记5 GoF之工厂模式

Spring学习笔记4 Bean的作用域_biubiubiu0706的博客-CSDN博客 出了GoF23种设计模式.还有javaee的设计模式(DAO模式,MVC模式) 设计模式:是一种可以被重复利用的解决方案 GoF23种设计模式可分为三大类: 创建型(5个):解决对象创建问题. 单例模式&#xff0c;工厂方法模式&#x…

Windows--Python永久换下载源

1.新建pip文件夹&#xff0c;注意路径 2.在上述文件中&#xff0c;新建文件pip.ini 3.pip.ini记事本打开&#xff0c;输入内容&#xff0c;保存完事。 [global] index-url https://pypi.douban.com/simple

​旅行季《乡村振兴战略下传统村落文化旅游设计》许少辉八一著作想象和世界一样宽广

​旅行季《乡村振兴战略下传统村落文化旅游设计》许少辉八一著作想象和世界一样宽广

计算机毕业设计 基于微信小程序的校园商铺系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

基于SpringBoot的甘肃非物质文化网站设计与实现

目录 前言 一、技术栈 二、系统功能介绍 用户信息管理 商品分类管理 申请信息管理 订单信息管理 三、核心代码 1、登录模块 2、文件上传模块 3、代码封装 前言 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#x…

lv5 嵌入式开发-6 线程的取消和互斥

目录 1 线程通信 – 互斥 2 互斥锁初始化 – pthread_mutex_init 3 互斥锁销毁 pthread_mutex_destroy 4 申请锁 – pthread_mutex_lock 5 释放锁 – pthread_mutex_unlock 6 读写锁 7 死锁的避免 8 条件变量&#xff08;信号量&#xff09; 9 线程池概念和实现 9.1 …

bean的生命周期

配置生命周期 方法一:在配置文件中配置这些属性 方法二:在类上实现接口 生命周期的具体过程 补充 bean的销毁方法默认是不会触发的 必须手动关闭容器,在虚拟机退出之前(程序执行完虚拟机就退出了) configurablleApplicationContext中才有close这个方法

windows下实现mysql8的主从复制

1、下载mysql8的安装包 MySQL :: Download MySQL Community Server 2、放到指定目录进行解压&#xff0c;更改名称为mysql-8.1.0-winx64-master,并复制一份作为从数据库 3、在bin目录下创建一个my.ini文件 添加如下内容 [mysqld] basedir"D:/soft/mysql/mysql-8.1.0-win…

Linux 系统死机后挽救措施

一、背景 因我们日常使用Linux系统过程中&#xff0c;会不时遇到系统崩溃的事&#xff0c;但这时系统界面除了呈现一片告警字符外&#xff0c;无发执行任何其他操作&#xff0c;留给我们的要不重启&#xff0c;要不就是尴尬等待指令。那面对会这种情况&#xff0c;还到底有没有…

App Inventor 2 模拟sleep函数

App Inventor 2 原生没有 sleep 及相关函数&#xff0c;需要模拟实现&#xff0c;经过测试这里给出一个既简单又相对高效率的实现方案&#xff1a; 需要用到计时器组件&#xff1a; 实现代码如下&#xff1a; 代码原理非常简单&#xff0c;就是计算好要 sleep 到的时刻&#x…