插件使用
npm i @types/pizzipnpm i docxtemplaternpm i jszip-utilsnpm i file-savernpm i docxtemplater-image-module-freenpm i echarts
最近的公司的一个需求,需要下载带有图片的文档,找了半天,看了文档只能下载普通的,下载图片啥的需要收费,一年几百欧,然后没办法,先把图片这个模块暂时搁置了,然后在隔了半个月后,看到了一个demo,抱着试一试的想法,运行起了代码,然后就解决了这个每年需要多花费几百欧的需求。
/* html部分 */
<template>
<div id="docxExport">
<div @click="exportWord">
点击下载文档
</div>
</div>
</template>
html测试用的非常简单,不要在意
/* js */
import PizZip from 'pizzip'
import Docxtemplater from 'docxtemplater'
import JszipUtils from 'jszip-utils'
import FileSave from 'file-saver'
import ImageModule from 'docxtemplater-image-module-free'
import * as echarts from 'echarts'
插件的引入,如果只需要下载普通的文档,只需要引入前面4个插件就行
第五个插件是用来下载图片、图表用的;第六个就是专门用来渲染图表用的
data() {
return {
img: 'https://img-cloud.youjiaoyun.net/mp/0a802a40-4a4b-4121-aa88-1fc6367a7410.jpg',
img2: 'http://bhyf-file.oss-cn-hangzhou.aliyuncs.com/4578/1636526930976_4fb0c795.jpeg',
childs: [
{
name: '张三',
age: '18'
},
{
name: '李四',
age: '19'
}
],
imglist: [
'http://bhyf-file.oss-cn-hangzhou.aliyuncs.com/4578/1636526930976_4fb0c795.jpeg',
'https://img-cloud.youjiaoyun.net/mp/0a802a40-4a4b-4121-aa88-1fc6367a7410.jpg'
],
pnglist: []
}
},
/**
* 下载图片什么需要将格式转化为base64
* 图片转base64方法
*/
urlToBase64(url) {
return new Promise((resolve) => {
const image = new Image()
image.setAttribute('crossOrigin', 'Anonymous')
image.onload = function() {
const canvas = document.createElement('canvas')
canvas.width = image.width
canvas.height = image.height
canvas.getContext('2d').drawImage(image, 0, 0)
const result = canvas.toDataURL('image/png')
resolve(result)
}
image.src = url
})
},
/**
* base64转为ArrayBuffer
* 这个我也不知道为什么,我看最后下载打印的时候连接是base64格式的
*/
base64DataURLToArrayBuffer(dataURL) {
const base64Regex = /^data:image\/(png|jpg|svg|svg\+xml);base64,/
if (!base64Regex.test(dataURL)) {
return false
}
const stringBase64 = dataURL.replace(base64Regex, '')
let binaryString
if (typeof window !== 'undefined') {
binaryString = window.atob(stringBase64)
} else {
binaryString = new Buffer(stringBase64, 'base64').toString('binary')
}
const len = binaryString.length
const bytes = new Uint8Array(len)
for (let i = 0; i < len; i++) {
const ascii = binaryString.charCodeAt(i)
bytes[i] = ascii
}
return bytes.buffer
},
/**
* 导出word
*/
async exportWord() {
const _this = this
const pngs = []
this.imglist.forEach((v) => {
pngs.push(this.urlToBase64(v))
})
try {
const pnglist = await Promise.all(pngs)
this.pnglist = pnglist.map((v) => {
return {
url: v
}
})
} catch (error) {
console.log(error)
}
// echarts图表
var div = document.createElement('div')
div.setAttribute('style', 'width: 400px;height:200px;')
let option = {
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value'
},
series: [
{
data: [150, 230, 224, 218, 135, 147, 260],
type: 'line'
}
]
}
let myChart = echarts.init(div)
myChart.setOption(option)
// 将文件转为二进制
JszipUtils.getBinaryContent('news.docx', function(err, res) {
console.log(res)
if (err) {
throw err
}
let opts = {
centered: false,
fileType: 'docx'
}
opts.getImage = function(tagValue) {
if (tagValue.size && tagValue.data) {
return _this.base64DataURLToArrayBuffer(tagValue.data)
}
return _this.base64DataURLToArrayBuffer(tagValue)
}
opts.getSize = function(_, tagValue) {
if (tagValue.size && tagValue.data) {
return tagValue.size
}
return [200, 200] // word里面图片的尺寸
}
// 将文件转为zip文件
let pizZip = new PizZip(res)
let doc = new Docxtemplater()
doc.loadZip(pizZip)
doc.setOptions({
nullGetter: function() {
return ''
}
})
console.log(opts)
doc.attachModule(new ImageModule(opts))
// 设置填充内容
let a = {
image: myChart.getDataURL({
pixelRatio: 5, // 导出的图片分辨率比率,默认是1
backgroundColor: '#afdfe4', // 图表背景色
excludeComponents: ['toolbox'], // 忽略组件的列表
type: 'png' // 图片类型支持png和jpeg
}),
imgs: _this.pnglist
}
doc.setData(a)
// 进行内容填充
try {
doc.render()
} catch (error) {
// 抛出异常
let e = {
message: error.message,
name: error.name,
stack: error.stack,
properties: error.properties
}
console.log(e)
throw error
}
// 获取要下载的文件
let out = doc.getZip().generate({
type: 'blob',
mimeType:
'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
})
// 进行下载
FileSave(out, '带有图片的docx下载')
})
}
word格式
{%image} 就是正常的出现 {%%image} 居中出现 {#imgs}{url}{/imgs} 循环渲染
大致就是这样,里面还有些地方不是很明白,不过代码和人有一个能跑不就行了