每日小记 —— 利用docxtemplater插件将页面表格导出word文档
前言
周一早上刚来上班,"可爱"的产品经理就给我整个需求,让我一个上午把上星期做的表格(包含数据)在不借助后端的情况下,纯前端导出word,后来在网上一顿搜索找到了适配需求的插件-docxtemplater,首先声明一下:我这个项目是vue3,react的暂时没试过,下面简单介绍下使用方法。
安装插件
1、npm i docxtemplater
2、npm i docxtemplater-image-module-free(如果你需要的话,这是在文件中处理图片用的)
3、npm i pizzip
4、npm i file-saver(ts需要这样安装,npm i @types/file-saver)
封装组件
这里我把组件放在utils文件夹下,新增outword.js文件方便管理,下面是完整代码
import Docxtemplater from 'docxtemplater'
import PizZip from 'pizzip'
import JSZipUtils from 'jszip-utils'
import { saveAs } from 'file-saver'
export const ExportBriefDataDocx = (tempDocxPath, data, fileName, imgSize) => {
console.log(tempDocxPath, data, fileName, imgSize)
// 如果你不处理图片你可以不引入
var ImageModule = require('docxtemplater-image-module-free')
var expressions = require('angular-expressions')
var assign = require('lodash/assign')
var last = require('lodash/last')
expressions.filters.lower = function (input) {
if (!input) return input
return input.toLowerCase() // toLowerCase() 方法用于把字符串转换为小写。
}
function angularParser(tag) {
tag = tag.replace(/^.$/, 'this').replace(/(’|‘)/g, "'").replace(/(“|”)/g, '"')
const expr = expressions.compile(tag)
return {
get: function (scope, context) {
let obj = {}
const index = last(context.scopePathItem)
const scopeList = context.scopeList
const num = context.num
for (let i = 0, len = num + 1; i < len; i++) {
obj = assign(obj, scopeList[i])
}
obj = assign(obj, { $index: index })
return expr(scope, obj)
},
}
}
JSZipUtils.getBinaryContent(tempDocxPath, (error, content) => {
if (error) {
console.log(error)
}
expressions.filters.size = function (input, width, height) {
return {
data: input,
size: [width, height],
}
}
let opts = {}
opts = {
// 图像是否居中
centered: true,
}
opts.getImage = (chartId) => {
// 将base64的数据转为ArrayBuffer
return base64DataURLToArrayBuffer(chartId)
}
opts.getSize = function (img, tagValue, tagName) {
// 自定义指定图像大小
if (imgSize.hasOwnProperty(tagName)) {
return imgSize[tagName]
} else {
return [200, 200]
}
}
// 创建一个JSZip实例,内容为模板的内容
const zip = new PizZip(content)
// 创建并加载 Docxtemplater 实例对象
let doc = new Docxtemplater()
doc.attachModule(new ImageModule(opts))
doc.loadZip(zip)
doc.setOptions({ parser: angularParser })
doc.setData(data)
try {
// 呈现文档,会将内部所有变量替换成值,
doc.render()
} catch (error) {
const e = {
message: error.message,
name: error.name,
stack: error.stack,
properties: error.properties,
}
console.log('err', { error: e })
// 当使用json记录时,此处抛出错误信息
throw error
}
// 生成一个代表Docxtemplater对象的zip文件(不是一个真实的文件,而是在内存中的表示)
const out = doc.getZip().generate({
type: 'blob',
mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
})
// 将目标文件对象保存为目标类型的文件,并命名
saveAs(out, fileName)
})
}
文档模板编写
这里有个比较坑的问题,就是你得把你生成的word文档做个模板出来,这里我是这样弄的
我这里是个IOT的项目,具体的术语忽略,直接看重要的信息;
其中{shanMen},{duXieQi},{piaoXiang},{jianKangDu}这个四个数据我用{xxxx}这样的模板来表示,具体为啥这样来写,因为插件官网就是这么说的;
实际应用
主要工作都弄好了,下面就很简单了;
引入插件
import { ExportBriefDataDocx } from '@/utils/outword'
具体使用
// ExportBriefDataDocx('引用刚才我们写好的word文档', '你要展示的数据', '导出文件的名称')
注意!!!
还记得刚才我们写的模板中的内容么{shanMen},{duXieQi},{piaoXiang},{jianKangDu},所以传进去的数据格式,属性名称必须和模板中的名称相同。
所以这里的数据格式应该是:
const exportData = {
shanMen: '否',
duXieQi: '否',
piaoXiang: '是',
jianKangDu: '88',
}
// ExportBriefDataDocx('刚才写的模板的地址', '需要展示的数据', '导出报告的名称')
function exportReport() {
ExportBriefDataDocx('/export-template/评估报告.docx', exportData, `评估报告.docx`)
}
结果
我们可以看到数据已经上来了。
如果你想把数据做成动态,那就和后端做一下交互就好了。
后记
这里参考了一篇文章,还有docxtemplater官网,链接如下
docxtemplater官网:docxtemplater.com/
转载自:https://juejin.cn/post/7235898992293478461