小工具知识网

当前位置: 首页 > 行业知识 > Vue中前端导出word文件

行业知识

Vue中前端导出word文件

2026-11-09 01:53:43 来源:互联网转载

很多时候在工作中会碰到完全由前端导出word文件的需求,因此特地记录一下比较常用的几种方式。

一、提供一个word模板

该方法提供一个word模板文件,数据通过参数替换的方式传入word文件中,灵活性较差,适用于简单的文件导出。需要依赖:docxtemplater、file-saver、jszip-utils、pizzip。

javascript复制代码import Docxtemplater from "docxtemplater";import { saveAs } from "file-saver";import JSZipUtils from "jszip-utils";import PizZip from "pizzip";export function downloadWithTemplate(path, data, fileName) {  JSZipUtils.getBinaryContent(path, (error, content) => {    if (error) throw error;    const zip = new PizZip(content);    const doc = new Docxtemplater().loadZip(zip);    doc.setData({      ...data.form,      // 循环项参数      list: data.list,      outsideList: data.outsideList,    });    try {      doc.render();    } catch (error) {      const e = {        message: error.message,        name: error.name,        stack: error.stack,        properties: error.properties,      };      ElMessage.error("文件格式有误!");      throw error;    }    const out = doc.getZip().generate({      type: "blob",      mimeType:        "application/vnd.openxmlformats-officedocument.wordprocessingml.document",    });    saveAs(out, fileName);  });}let data = {    form: {      title: "这是word标题",      test: "这是表单1的数据",      test1: "111",      test2: 222,      test3: 333,    },    outsideList: [      {        list: [          {            index: 0,            table: "表格第一项",            table1: "表格第二项",            table2: "表格第三项",          },          {            index: 1,            table: "表格第一项",            table1: "表格第二项",            table2: "表格第三项",          },        ],      },      {        list: [          {            index: 0,            table: "表格第一项",            table1: "表格第二项",            table2: "表格第三项",          },          {            index: 1,            table: "表格第一项",            table1: "表格第二项",            table2: "表格第三项",          },        ],      },    ],  };    downloadWithTemplate("template.docx", data, "模板word.docx")  

调用downloadWithTemplate方法即可导出如下文件:

注: 上述方法中的path参数为你在vue项目中存放公共文件的位置,在vue2中为static文件夹下,在vue3中为public文件夹下。

二、根据html代码转换为word文件(推荐)

顾名思义,这个方法就是将我们在页面上书写的html代码直接转换成word文件,这也是我最推荐的一种方法,因为大部分的样式可控,且毕竟是我们较为熟悉的方式。需要插件: html-docx-js-typescript、file-saver。

xml复制代码import { saveAs } from "file-saver";import { asBlob } from "html-docx-js-typescript"; export function downloadWordWithHtmlString(html, name) {  let htmlString = `              Document        ${html}      `;  asBlob(htmlString).then((data) => {    saveAs(data, `${name}.docx`);  });}  `

使用案例:

ini复制代码  

word标题

1111 合并单元格 最长的一项
222 222 222 222
1111 合并包括此行在内的下面三行
222
3333
50
let word = ref(null);downloadWordWithHtmlString(word.value.innerHTML, 'html字符串word.docx');

生成的word文件可以看到效果和在网页中的html代码一样:

另外需要注意的是,若是需要在word中添加分页符,在需要分页的内容处添加CSS属性page-break-before即可。此时在浏览器上打印出innerHTML值会发现:

mdn上介绍page-break-before属性已经被break-before属性替代,但是经过我实际测试发现当html字符串是page-break: always时生成的word文件没有分页效果,反而是将其替换回page-break-before后实现了分页效果。若有大神知道这是什么问题还望不吝赐教。 因此需要在downloadWordWithHtmlString方法中添加一句正则: htmlString = htmlString.replace( /break-(after|before): page/g, "page-break-$1: always;" );,此时就能实现分页效果。

三、使用docx插件

第二种方法有个很致命的问题就是它无法在生成的word文件中添加图片页眉,我搜遍了npm也只找到一个能添加文字页眉的插件: html-docx-ts要想实现这个需求,就需要用到docx插件。 docx官网的介绍是"Easily generate and modify .docx files with JS/TS. Works for Node and on the Browser.",意味着是一个专门用于生成word和修改word的文件。该插件就需要一个一个去配置你要生成的项,然后组合成一个word。一个简单的案例是:

css复制代码import {  Document,  Paragraph,  Header,  TextRun,  Table,  TableRow,  TableCell,  WidthType,  Packer,} from "docx";import { saveAs } from "file-saver";const document = new Document({    sections: [      {        headers: {          default: new Header({            children: [new Paragraph("我是页眉")],          }),        },        children: [          new Paragraph({            children: [              new TextRun({                text: "我是文字内容",                size: 16,                bold: true,              }),            ],          }),          new Table({            columnWidths: [1500, 7500],            rows: [              new TableRow({                children: [                  new TableCell({                    width: {                      size: 1500,                      type: WidthType.DXA,                    },                    children: [                      new Paragraph({                        alignment: "center",                        children: [                          new TextRun({                            text: "测试",                            size: 24,                            font: {                              name: "楷体",                            },                          }),                        ],                      }),                    ],                  }),                ],              }),            ],          }),        ],      },    ],  });    Packer.toBlob(document).then((blob) => {    saveAs(blob, "test.docx");  });

导出的word文件形式为:

下面是我个人总结的比较常见能用到的功能和配置项:

css复制代码// 导出文字1.new Paragraph(text) -> 默认字体样式: 宋体,五号字2.new Paragraph({    children: [      new TextRun({        text: "我是文字内容",        size: 16, // 对应word中的字体大小8        bold: true, // 是否加粗        underline: {          type: UnderlineType.SINGLE,          color: "#2e32ee",        }, // 下划线类型及颜色        font: {          name: "仿宋", // 只要是word中有的字体类型都可以生效        },      }),    ],    indent: {      left: 100,    }, // 离左边距离 类似于margin-left    spacing: {      before: 150,      after: 200,    }, // 离上边和下边的距离 类似于margin-top/bottom    alignment: "center", // 对齐方式    pageBreakBefore: true, // 是否在这段文字前加入分页符  })   // 导出表格new Table({  columnWidths: [1500, 7500], // 表示单行有几项,总宽度是9000,对应宽度;  rows: [    new TableRow({      children: [        new TableCell({          width: {            size: 1500, // 需与columnWidths的第一项对应            type: WidthType.DXA, // 官网的介绍是Value is in twentieths of a point            // 因为表格的总宽度是以twips(每英寸的1/20)为单位进行计算的          },          children: [            new Paragraph({              alignment: "center",              children: [                new TextRun({                  text: "测试",                  size: 24,                  font: {                    name: "楷体",                  },                }),              ],            }),          ],        }),        new TableCell({          width: {            size: 7500,            type: WidthType.DXA,          },          children: [            new Paragraph('ccc'),          ],          margins: {            top: 500,            bottom: 500,            left: 500          } // 类似于单元格内容的padding        }),      ],    }),  ],})// 导出图片new Paragraph({  children: [    new ImageRun({      data: "base64", // 图片需转成base64的形式      transformation: {        width: 100,        height: 30,      }, // 图片宽高    }),  ],})// 设置页眉页脚headers: {  default: new Header({    children: [new Paragraph("我是页眉")],  }),},footers: {  default: new Footer({    children: [new Paragraph("我是页脚")],  }),}

下面是一个完整的使用案例:

css复制代码const document = new Document({  sections: [    {      headers: {        default: new Header({          children: [            new Paragraph({              children: [                new ImageRun({                  data: "data:image/jpeg;base64,...",                  transformation: {                    width: 150,                    height: 150,                  },                }),              ],            }),          ],        }),      },      footers: {        default: new Footer({          children: [new Paragraph("我是页脚")],        }),      },      children: [         new Paragraph("第一行直接默认形式"),         new Paragraph({           children: [             new TextRun({               text: "下一页",             }),           ],           pageBreakBefore: true,         }),         new Table({           columnWidths: [1500, 7500],           rows: [             new TableRow({               children: [                 new TableCell({                   width: {                     size: 1500,                     type: WidthType.DXA,                   },                   children: [                     new Paragraph({                       alignment: "center",                       children: [                         new TextRun({                           text: "测试",                           size: 24,                           font: {                             name: "楷体",                           },                         }),                       ],                     }),                   ],                 }),                 new TableCell({                   width: {                     size: 7500,                     type: WidthType.DXA,                   },                   children: [                     new Paragraph({                       children: [                         new ImageRun({                           data: "data:image/jpeg;base64,...",                           transformation: {                             width: 150,                             height: 150,                           },                         }),                       ],                     }),                   ],                   margins: {                     top: 500,                     bottom: 500,                    left: 500,                  },                }),              ],            }),          ],        }),      ],    },  ],});Packer.toBlob(document).then((blob) => {  saveAs(blob, "test.docx");});

此时导出的word文件如下:

学习更多vue开发知识请下载​​CRMEB开源商城​​附件学习

上一篇:git 使用的一般流程(只做记录)

下一篇:轻松下载歌曲指南,一步步教你如何精准获取心仪歌曲!