前端如何导出doc文档-docxtemplater

摘要:

为减少服务器压力,统计文档的导出需要前端实现,后端仅返回统计数据。本文将介绍使用docxtemplater导出文档,纯前端浏览器导出。

安装依赖

bash 复制代码
npm i docxtemplater pizzip docxtemplater-image-module-free file-saver

依赖说明:

  1. docxtemplater:导出模板文档库
  2. pizzip:加载资源文件内容、对模版内容进行解压及压缩。
  3. docxtemplater-image-module-free:对图片处理的模块(没有图片可不安装)。
  4. file-saver:将文件保存到本地

docxtemplater语法

{str} 文字
{%img} 图片
{#list}{/list} 循环、if判断
{#list}{/list}{^list}{/list} if else
{@rawXml} 原始xml,最强大的功能,如:要对表格列循环、插入任意样式的内容。

模板效果如下:

编写代码

获取模板内容

  1. 如果模板文件时在远程服务器,通过url获取,使用此方法
ts 复制代码
import PizZipUtils from 'pizzip/utils/index.js';

/**
 * 获取模板文件内容
 * @param templateFile 模版地址url
 * @returns
 */
function getFileBinaryString(templateFile: string): Promise<ArrayBuffer> {
  return new Promise((resolve, reject) => {
    PizZipUtils.getBinaryContent(templateFile, (err, content: any) => {
      if (err) {
        return reject(err);
      }
      resolve(content as ArrayBuffer);
    });
  });
}
  1. 如果文件是本地选择的文件,使用此方法获取
ts 复制代码
/**
 * 获取模板文件内容
 * @param blob 模版文件,通过input[type="file"]获取e.target.files[0]
 * @returns
 */
function getFileBinaryString(blob: Blob): Promise<ArrayBuffer> {
  return new Promise((resolve, reject) => {
    const file = new FileReader();
    file.onload = () => {
      resolve(file.result as ArrayBuffer);
    };
    file.onerror = reject;
    file.readAsArrayBuffer(blob);
  });
}

图片导出配置(没有图片可不配置)

ts 复制代码
import PizZipUtils from 'pizzip/utils/index.js';

const imageOpts = {
  // 获取图片内容
  getImage: (tagValue, tagName) => {
    return new Promise((resolve, reject) => {
      PizZipUtils.getBinaryContent(tagValue, (error, content) => {
        if (error) {
          return reject(error);
        }
        return resolve(content);
      });
    });
  },
  // 获取图片大小
  getSize: (img, tagValue, tagName) => {
    return new Promise((resolve, reject) => {
      const image = new Image();
      image.onload = () => {
        resolve([image.width, image.height]);
      };
      image.onerror = (e) => {
        console.log('load image error', img, tagValue, tagName, e);
        reject(e);
      };
      image.src = tagValue;
    });
  },
};

生成文档

ts 复制代码
import PizZip from 'pizzip';
import DocxTemplater from 'docxtemplater';
import ImageModule from 'docxtemplater-image-module-free';

/**
 * 根据模板生成文档文件
 * @param template 模版url
 * @param fileData 填充的数据
 * @returns
 */
export async function generateDocxFile(template: string, fileData: Record<string, any>) {
  // 获取模板内容,根据自己的情况,调用第一步的方法,这里是用远程url的方式获取的
  const templateData = await getFileBinaryString(template);
  // 使用PizZip处理模板数据
  const zip = new PizZip(templateData);
  // 初始化模板。没有图片可以不配置 modules
  const doc = new DocxTemplater(zip, { modules: [new ImageModule(imageOpts)] });
  // 往模板填充数据
  await doc.renderAsync(fileData);
  // 生成blob数据,用于下载
  const out = doc.getZip().generate({
    type: 'blob',
    mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
  });
  return out;
}

外部调用

ts 复制代码
import { saveAs } from 'file-saver';

async function handleExportDocx() {
  const templateUrl = 'https://xxxxx.oss-cn-beijing.aliyuncs.com/template/xxx.docx';
  const out = await generateDocxFile(templateUrl, {
    // 字符串
    title: '标题',
    // 数组
    users: [
      { id: 1, name: '张三' },
      { id: 2, name: '李四' },
      { id: 3, name: '王五' },
    ],
    // 图片的远程地址
    imgUrl: 'https://xxxxx.oss-cn-beijing.aliyuncs.com/xxx.png',
    // 通过echarts生成的图表图片数据、canvas数据
    imgDataUrl: echarts.getDataURL(),
    // 布尔
    isBuy: true
  });
  saveAs(out, `xxxx.docx`);
}

最终效果

完整代码

ts 复制代码
import PizZip from 'pizzip';
import DocxTemplater from 'docxtemplater';
import ImageModule from 'docxtemplater-image-module-free';
import PizZipUtils from 'pizzip/utils/index.js';
import { saveAs } from 'file-saver';

const imageOpts = {
  getImage: (tagValue, tagName) => {
    return new Promise((resolve, reject) => {
      PizZipUtils.getBinaryContent(tagValue, (error, content) => {
        if (error) {
          return reject(error);
        }
        return resolve(content);
      });
    });
  },
  getSize: (img, tagValue, tagName) => {
    return new Promise((resolve, reject) => {
      const image = new Image();
      image.onload = () => {
        resolve([image.width, image.height]);
      };
      image.onerror = (e) => {
        console.log('图片加载失败', img, tagValue, tagName, e);
        reject(e);
      };
      image.src = tagValue;
    });
  },
};

/**
 * 获取模板文件内容
 * @param templateFile 模版地址url
 * @returns
 */
function getFileBinaryString(templateFile: string): Promise<ArrayBuffer> {
  return new Promise((resolve, reject) => {
    PizZipUtils.getBinaryContent(templateFile, (err, content: any) => {
      if (err) {
        reject(err);
        return;
      }
      resolve(content as ArrayBuffer);
    });
  });
}

/**
 * 根据模板生成文档文件
 * @param template 模版url
 * @param fileData 填充的数据
 * @returns
 */
export async function generateDocxFile(template: string, fileData: Record<string, any>) {
  const templateData = await getFileBinaryString(template);
  const zip = new PizZip(templateData);
  const doc = new DocxTemplater(zip, { modules: [new ImageModule(imageOpts)] });
  await doc.renderAsync(fileData);
  const out = doc.getZip().generate({
    type: 'blob',
    mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
  });
  return out;
}

// 导出文件
async function handleExportDocx() {
  const templateUrl = 'https://xxxxx.oss-cn-beijing.aliyuncs.com/template/xxx.docx';
  const out = await generateDocxFile(templateUrl, {
    // 字符串
    title: '标题',
    // 数组
    users: [
      { id: 1, name: '张三' },
      { id: 2, name: '李四' },
      { id: 3, name: '王五' },
    ],
    // 图片的远程地址
    imgUrl: 'https://xxxxx.oss-cn-beijing.aliyuncs.com/xxx.png',
    // 通过echarts生成的图表图片数据、canvas数据
    imgDataUrl: echarts.getDataURL(),
    // 布尔
    isBuy: true
  });
  saveAs(out, `xxxx.docx`);
}

{@rawXml}

将docx文件保存为xml文件,就可以看的原始xml,可以把自己需要复制出来,修改成自己需要的内容,进行插入。

更多模块

官方文档

评论

0条评论

logo

暂无内容,去看看其他的吧~