docxtemplater避坑!!! 前端导出word怎么插入本地图片或base64 有完整示例

docxtemplater库实现前端通过模板导出word,遇到需求,要插图片并转成word并导出,在图片转换这块遇到了问题,网上查示例大多都跑不通,自己琢磨半天,总算搞明白了。

附上清晰完整示例,供参考。

如有不懂,私我询问!

首先需要一个word文件作为模板

必须是docx文件!!!

{%} 代表图片 xgq是变量

安装需要的包

bash 复制代码
npm install docxtemplater
npm install docxtemplater-image-module-free
npm install pizzip
npm install file-saver
npm install html2canvas # 如需截图的话 安装
ts 复制代码
import Docxtemplater from 'docxtemplater';
import { saveAs } from 'file-saver';
import PizZip from 'pizzip';
import ImageModule from 'docxtemplater-image-module-free';
import html2canvas from 'html2canvas';
import image from './20240522152640.jpg';
import docx from './test.docx';

插入本地图片并转换

ts 复制代码
const imageData = await fetch(image);
const imageArrayBuffer = await imageData.arrayBuffer();
const imgDataDict: Record<string, ArrayBuffer> = {
  xgq: imageArrayBuffer,
};
const docxData = await fetch(docx);
const docxArrayBuffer = await docxData.arrayBuffer();
const zip = new PizZip(docxArrayBuffer);
const doc = new Docxtemplater(zip, {
  paragraphLoop: true,
  linebreaks: true,
  modules: [
    new ImageModule({
      getImage: (value: string, key: string) => {
        return imgDataDict[key];
      },
      getSize: (afterValue: ArrayBuffer, value: string, key: string) => {
        return [400, 400];
      },
    }),
  ],
});
doc.render({
  xgq: "xgq", // 这里得是字符串否则会报错
});
const blob = doc.getZip().generate({
  type: "blob",
  mimeType:
    "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
});
saveAs(blob, "download.docx");

插入base64图片并转换

ts 复制代码
const base64 =
  "data:image/jpeg;base64,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";
const imageArrayBuffer = base64DataURLToArrayBuffer(base64);
const imgDataDict: Record<string, ArrayBuffer> = {
  xgq: imageArrayBuffer,
};
const docxData = await fetch(docx);
const docxArrayBuffer = await docxData.arrayBuffer();
const zip = new PizZip(docxArrayBuffer);
const doc = new Docxtemplater(zip, {
  paragraphLoop: true,
  linebreaks: true,
  modules: [
    new ImageModule({
      getImage: (value: string, key: string) => {
        return imgDataDict[key];
      },
      getSize: (afterValue: ArrayBuffer, value: string, key: string) => {
        return [400, 400];
      },
    }),
  ],
});
doc.render({
  xgq: "xgq", // 这里得是字符串否则会报错
});
const blob = doc.getZip().generate({
  type: "blob",
  mimeType:
    "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
});
saveAs(blob, "download.docx");
ts 复制代码
const base64DataURLToArrayBuffer = (dataURL: string) => {
  const base64Regex = /^data:image\/(png|jpg|jpeg|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;
};

截图某个网页区域并插入转换

ts 复制代码
<div id="test" style={{ border: "1px solid red", width: 300 }}>
  <div>截图</div>
  <button type="button">666</button>
  <br />
  <img src={image} />
</div>;
ts 复制代码
const dom: any = document.getElementById("test");
const canvas = await html2canvas(dom, {
  useCORS: true,
  scale: 5,
});
const imageDataURL = canvas.toDataURL("image/png");
const response = await fetch(imageDataURL);
const imageArrayBuffer = await response.arrayBuffer();
const imgDataDict: Record<string, ArrayBuffer> = {
  xgq: imageArrayBuffer,
};
const docxData = await fetch(docx);
const docxArrayBuffer = await docxData.arrayBuffer();
const zip = new PizZip(docxArrayBuffer);
const doc = new Docxtemplater(zip, {
  paragraphLoop: true,
  linebreaks: true,
  modules: [
    new ImageModule({
      getImage: (value: string, key: string) => {
        return imgDataDict[key];
      },
      getSize: (afterValue: ArrayBuffer, value: string, key: string) => {
        return [400, 400];
      },
    }),
  ],
});
doc.render({
  xgq: "xgq", // 这里得是字符串否则会报错
});
const blob = doc.getZip().generate({
  type: "blob",
  mimeType:
    "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
});
saveAs(blob, "download.docx");
相关推荐
前端小小王11 分钟前
React Hooks
前端·javascript·react.js
迷途小码农零零发20 分钟前
react中使用ResizeObserver来观察元素的size变化
前端·javascript·react.js
娃哈哈哈哈呀43 分钟前
vue中的css深度选择器v-deep 配合!important
前端·css·vue.js
旭东怪1 小时前
EasyPoi 使用$fe:模板语法生成Word动态行
java·前端·word
ekskef_sef3 小时前
32岁前端干了8年,是继续做前端开发,还是转其它工作
前端
sunshine6413 小时前
【CSS】实现tag选中对钩样式
前端·css·css3
真滴book理喻4 小时前
Vue(四)
前端·javascript·vue.js
蜜獾云4 小时前
npm淘宝镜像
前端·npm·node.js
dz88i84 小时前
修改npm镜像源
前端·npm·node.js
Jiaberrr4 小时前
解锁 GitBook 的奥秘:从入门到精通之旅
前端·gitbook