需求介绍
在项目中,我们可以借助后端返回文件流实现文件下载。如果前端有数据,也可以借助前端框架进行下载。本文将介绍如何在前端纯js实现word文档生生成。
需求变化
根据产品需要,文件以word形式导出,并期望可以通过pdf形式实现预览。实现具体思路如下:
工具介绍
实现此功能需要使用到docxtemplater、jszip-utils、jszip、FileSaver等js插件
- docxtemplater是一种邮件合并工具,它以编程方式使用,处理条件、循环,并且可以扩展为表格、HTML、图像等参考链接:docxtemplater.readthedocs.io/en/latest/i…
- jszip-utils是与jszip一起使用的跨浏览器的工具库。参考链接:stuk.github.io/jszip-utils…
- jszip是一个用于创建、读取和编辑.zip文件的JavaScript库,且API的使用也很简单。参考链接:stuk.github.io/jszip/
- FileSaver.js 是在客户端保存文件的解决方案,非常适合需要生成文件,或者保存不应该发送到外部服务器的敏感信息的应用。参考链接: www.cnblogs.com/yunser/p/76…
实现步骤
- 完成word模板
首先,根据需要导出的word文件的要求,先使用word制作出模板,数据使用
{变量}代替,注意:{}语法不能出现空格 - 安装依赖
- cnpm install docxtemplater pizzip --save
- cnpm install jszip-utils --save
- cnpm install jszip --save
- cnpm install file-saver --save
- 实现方式
- 前端生成word文件--base64格式
- 将base64转成文件传给后端,后端将文件解码后生成pdf文件
- 前端调用查看文件接口获取base64文件流,通过iframe实现文件预览
引入js文件
import PizZip from "pizzip"
import JSZipUtils from "jszip-utils"
import { sendReport } from '@/api/grouping'
import { Message } from 'element-ui'
/**
导出docx
1. @param { String } tempDocxPath 模板文件路径
2. @param { Object } data 文件中传入的数据
3. @param { String } fileName 导出文件名称
4. @param { group_id } group_id 导出文件id--可选参数
5. @param { group_id } callback 导出文件后的回调函数--可选参数
*/
export const exportDocx = (tempDocxPath, data, fileName, group_id, type, callback) => {
// 读取并获得模板文件的二进制内容exportDocx
JSZipUtils.getBinaryContent(tempDocxPath, (error, content) => {
if (error) {
throw error
}
const zip = new PizZip(content)
const doc = new Docxtemplater().loadZip(zip)
doc.setData(data)
try {
doc.render()
} catch (error) {
const e = {
message: error.message,
name: error.name,
stack: error.stack,
properties: error.properties,
}
console.log({
error: e,
})
throw error
}
const out = doc.getZip().generate({
type: "blob",
mimeType:
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
})
function getBase64(out) {
let reader = new FileReader()
return new Promise((resolve) => {
reader.readAsDataURL(out)
return reader.onload = function (e) {
resolve(base64toFile(e.target.result))
}
})
}
getBase64(out).then((res) => {
let params = {
simulationID: group_id,
report_type: 'score',
report_data: res,
type: 'sc'
}
sendReport(params).then((res) => {
callback()
Message.success('生成成功')
})
})
// 第一个参数dataUrl是一个base64的字符串。第二个参数是文件名可以随意命名
function base64toFile(dataurl, filename = 'file') {
let arr = dataurl.split(',');
let mime = arr[0].match(/:(.*?);/)[1];
// suffix是该文件的后缀
let suffix = mime.split('/')[1];
// atob 对经过 base-64 编码的字符串进行解码
let bstr = atob(arr[1]);
// n 是解码后的长度
let n = bstr.length;
// Uint8Array 数组类型表示一个 8 位无符号整型数组 初始值都是 数子0
let u8arr = new Uint8Array(n);
// charCodeAt() 方法可返回指定位置的字符的 Unicode 编码。这个返回值是 0 - 65535 之间的整数
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
// new File返回File对象 第一个参数是 ArraryBuffer 或 Bolb 或Arrary 第二个参数是文件名
// 第三个参数是 要放到文件中的内容的 MIME 类型
return new File([u8arr], `${filename}.${suffix}`, {
type: mime,
});
}
// saveAs(out, fileName)
// window.URL.createObjectURL(out)
})
}
pdf文件预览iframe式
<iframe width="100%" height="100%" :src="pdfUrl" name="成绩评定报告" frameborder="0"></iframe>
let params = {
type: "ck",
simulationID: row.group_id,
report_type: "score",
};
sendReport(params).then((res) => {
this.reportTitle = row.group_id + "成绩评定报告";
this.openViewPdf = true;
let url = "data:application/pdf;base64," + res.pdf;
this.pdfUrl = url;
// window.open();
// document.open();
// document.write(iframe);
// document.close();
});
},