前端 word 导出
前端的常规导出,一般是 excel,下载图片什么。word 的导出有点不太一样。
导出前的准备,安装相关依赖
import Docxtemplater from 'docxtemplater' import PizZip from 'pizzip' import PizZipUtils from 'pizzip/utils/index.js' import { saveAs } from 'file-saver' import ImageModule from 'docxtemplater-image-module-free'
要新新建一个 word 的文件,中间的值用 {} ,类似于 tsx 或者 jsx 的写法,和 src 平级新建一个名称为 public 的文件夹
index.docx 的内容
第一个箭头,是常规的对象赋值,第二个,是表格循环,第三个是图片的显示
export const exportWord = ({ templateName = 'index.docx', docData = {}, fileName = '', fileType = 'docx' }: any) => { const base64DataURLToArrayBuffer = (dataURL: any) => { const base64Regex = /^data:image\/(png|jpg|jpeg|svg|svg\+xml);base64,/ const stringBase64 = dataURL.replace(base64Regex, '') let binaryString if (typeof window !== 'undefined') { binaryString = window.atob(stringBase64) } else { binaryString = Buffer.from(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 } const getBase64 = (img: any) => { function getBase64Image({ image, width, height }: any) { const canvas = document.createElement('canvas') canvas.width = width || image.width canvas.height = height || image.height const ctx: any = canvas.getContext('2d') ctx.drawImage(image, 0, 0, canvas.width, canvas.height) var dataURL = canvas.toDataURL() return dataURL } var image = new Image() image.crossOrigin = '' image.src = img return new Promise((resolve, reject) => { image.onload = function () { resolve(getBase64Image({ image })) } }) } loadFile(`/${templateName}`, function (error: any, content: any) { if (error) { throw error } const imageOpts = { getImage: async (tagValue: any, tagName: any) => { const base64Regex = /^data:image\/(png|jpg|jpeg|svg|svg\+xml);base64,/ let newValue: any = '' if (base64Regex.test(tagValue)) { newValue = base64DataURLToArrayBuffer(tagValue) } else if (tagValue.includes('http')) { await getBase64(tagValue).then((data) => { newValue = base64DataURLToArrayBuffer(data) }) } else { await PizZipUtils.getBinaryContent(tagValue, function (error, content) { if (!error) { newValue = content } }) } return newValue }, getSize: function (img: any, tagValue: any, tagName: any) { return [150, 150] } } const imageModule = new ImageModule(imageOpts) const zip = new PizZip(content) const doc = new Docxtemplater() .loadZip(zip) .setOptions({ paragraphLoop: true, linebreaks: true, nullGetter: nullGetter as any }) .attachModule(imageModule) .compile() doc.renderAsync(docData).then(function () { const out = doc.getZip().generate({ type: 'blob', mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' }) saveAs(out, `${fileName || new Date().getTime()}.${fileType}`) }) }) }
图片的导出,如果是本地的话,填写正确的引入地址,也以直接导出 base64 格式的图片,网络图片,也是需要先转换成 bas464,再导出。网络图片导出有一个小坑,就是跨域问题。一般是用 jq 的一个方法,具体可以再查一下。