这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助

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

一、提供一个word模板

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

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。

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`);
});
}

使用案例:

<div ref="word">
<h3 style="text-align: center">word标题</h3>
<table
border="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。一个简单的案例是:

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文件形式为:

面是我个人总结的比较常见能用到的功能和配置项:

// 导出文字
1.new Paragraph(text) -> 默认字体样式: 宋体,五号字
2.new Paragraph({
children: [
new TextRun({
text: "我是文字内容",
size: 16, // 对应word中的字体大小8
bold: true, // 是否加粗
underline: {
type: UnderlineType.SINGLE,
color: "#2e32ee",
}, // 下划线类型及颜色
font: {
name: "仿宋", // 只要是word中有的字体类型都可以生效
},
}),
],
indent: {
left: 100,
}, // 离左边距离 类似于margin-left
spacing: {
before: 150,
after: 200,
}, // 离上边和下边的距离 类似于margin-top/bottom
alignment: "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("我是页脚")],
}),
}

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

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文件如下:

本文转载于:

https://juejin.cn/post/7269022955471749131

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

记录--Vue中前端导出word文件的更多相关文章

  1. vue项目前端导出word文件(bug解决)

    摘要:之前项目中导出价格表是由后端实现,前端只需要调用接口下载word即可,后来业务改变比较大,word模版需要一直改动,后端改起来相对麻烦,后来直接前端自己定义模版,实现下载word文档. 一.需要 ...

  2. 纯前端导出pdf文件

    纯前端js导出pdf,已经用于生产环境. 工具: 1.html2canvas,一种让html转换为图片的工具. 2.pdfmake或者jspdf ,一种生成.编辑pdf,并且导出pdf的工具. pdf ...

  3. java导出word文件

    java导出word文件 test5.ftl文件生存方法, 第一步:用word新建test5.doc,填写完整模板,将需导出数据用${}代替 第二步:将test5.doc另存为test5.xml 第三 ...

  4. PDF.Js的使用—javascript中前端显示pdf文件

    PDF.Js的使用—javascript中前端显示pdf文件 写于2018/12/6 起因是一个图片展示页面需要展示pdf格式的文件,所以查了半天决定使用pdf.js,我也不求有多了解它,能实现我想要 ...

  5. 记录vue中一些有意思的坑

    记录vue中一些有意思的坑 'message' handler took 401ms 在出现这个之前,我一直纠结于 是如何使用vue-router或者不使用它,通过类似的v-if来实现.结果却出现这个 ...

  6. Vue中ESlint配置文件.eslintrc文件

    很久没有分享和更新过了 今天就给大家分享一篇 Vue中ESlint配置文件.eslintrc文件详解吧 ------------------------------------------------ ...

  7. 利用模板导出文件(二)之jacob利用word模板导出word文件(Java2word)

    https://blog.csdn.net/Fishroad/article/details/47951061?locationNum=2&fps=1 先下载jacob.jar包.解压后将ja ...

  8. web前端导出csv文件

    前言 导出文件,使用最多的方式还是服务器端来处理.比如jsp 中使用response 的方式. 但是,有时候可能就想使用web 前端是否也可以把页面上的内容导出来呢? 比如说,导出页面的一个表格. 这 ...

  9. vue中配置axios.js文件,发送请求

    为了统一管理请求,每个项目都会去配置axios:而不是在vue中直接使用,那样不好维护等等 下面是我配置的最基础的axios文件 第一步:首先新建一个axios文件,我是放在router文件下的 im ...

  10. vue中打包后vendor文件包过大

    vue中webpack打包后vendor.xxx.js文件一般都特别大,其原因是因为我们引用的依赖都被压缩成一个js文件,这样会导致vendor文件过大.页面加载速度过慢,影响用户体验.所以我们就要把 ...

随机推荐

  1. Python Rich:美化终端显示效果

    Rich库的功能就像它的名字一样,使Python编程更加丰富(rich),它帮助开发者在控制台(命令行)输出中创建丰富.多彩和具有格式化的文本. 本篇总结了如何使用Rich库让我们的命令行工具更加美观 ...

  2. 你应该知道的提升Visual Studio开发能力的5个技巧

    如果你像我一样,或许你也沉迷于开发者工具.这就是我喜欢 Visual Studio 的原因之一--它有无数的生产力技巧. 这篇文章将展示五个这样的技巧,这些技巧对我每天的工作都有帮助.请注意,这些仅适 ...

  3. 从零开始的react入门教程(七),react中的状态提升,我们为什么需要使用redux

    壹 ❀ 引 在前面的文章中,我们了解到react中的数据由props与State构成,数据就像瀑布中的水自上而下流动,属于单向数据流.而这两者的区别也很简单,对于一个组件而言,如果说props是外部传 ...

  4. NC13950 Alliances

    题目链接 题目 题目描述 树国是一个有n个城市的国家,城市编号为1∼n.连接这些城市的道路网络形如一棵树, 即任意两个城市之间有恰好一条路径.城市中有k个帮派,编号为1∼k.每个帮派会占据一些城市,以 ...

  5. Linux dmesg命令使用方法详解

    一.命令简介  dmesg(display message)命令用于显示开机信息.kernel 会将开机信息存储在 ring buffer 中.您若是开机时来不及查看信息,可利用 dmesg 来查看. ...

  6. 适用于Spring Boot Jar的启停部署脚本

    shell脚本参数 使用-z或-n对一个变量判空时, 若直接使用[ -n ARG ]这种形式,当{ARG}中有空格将会报错, line 27: [: sd: binary operator expec ...

  7. MYSQL服务无法启动:InnoDB: .\ibdata1 can't be opened in read-write mode

    今天在那做实验倒腾mysql数据库,后来发现服务无法启动,查看日志报错如下: 2015-01-07 17:48:54 9136 [ERROR] InnoDB: .\ibdata1 can't be o ...

  8. spring boot+layui实现增删改查实战

    说明: 最近在做一个后台,希望用一个现成的前端模板,找了一圈发现Layui比较合适.我知道很多人都有这个需求,为了使大家快速上手,我把自己写的最实用的增删改查案例完整的展示出来. 源码地址: http ...

  9. spring boot中使用定时任务

    1.在主类上添加EnableScheduling注解 package com.laoxu.gamedog; import org.springframework.boot.SpringApplicat ...

  10. QT - Day 3

    对话框 分类 模态对话框 QDialog dlg(this); dlg.resize(200,100); dlg.exec(); //窗口阻塞 非模态对话框 QDialog *dlg2 = new Q ...