vue项目:纯前端实现Word文档导出功能,使用第三方库生成word表格 合并单元格 导出手写复杂表格,并百分百还原word表格,一文搞定前端表格导出为word。

一、先看效果:

纯前端手撸格式,只需要有数据就行。

二、使用的库:

 "file-saver": "^2.0.5",
 "html-docx-js-typescript": "^0.1.5",

准备开始下包

npm install html-docx-js-typescript

npm install file-saver

三、创建一个JS文件:

最好是utils目录下  方便多次使用,文件名字随意 ,并把方法向外导出

import { saveAs } from "file-saver";
import { asBlob } from "html-docx-js-typescript";

export function downloadWordWithHtmlString(html, name) {
  let htmlString = `
  <!DOCTYPE html>
  <html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Document</title>
  </head>
  <body>
    ${html}
  </body>
  </html>
  `;
  asBlob(htmlString).then((data) => {
    saveAs(data, `${name}.docx`);
  });
}

四、开始使用:

1.准备数据:

const tableDataList = ref([
  {
    department: "销售A部",
    data: [
      {
        employee: "张三",
        job: "经理",
        lastMonth: 0.311,
        thisMonth: 2.687,
        total: 422.8,
        remark: '在职',
      },
      {
        employee: "李四",
        job: "经理",
        lastMonth: 3.704,
        thisMonth: 32.0026,
        total: 3250.7994,
        remark: '在职',
      },
      {
        employee: "王五",
        job: "经理",
        lastMonth: 1.588,
        thisMonth: 13.7203,
        total: 5133.14,
        remark: '实习',
      },
      {
        employee: "赵六",
        job: "经理",
        lastMonth: 0.83,
        thisMonth: 7.1712,
        total: 1680.8951,
        remark: '在职',
      },
    ],
  },
  {
    department: "销售B部",
    data: [
      {
        employee: "员工1",
        job: "经理",
        lastMonth: 6,
        thisMonth: 51.84,
        total: 13289.56,
        remark: '在职',
      },
      {
        employee: "员工2",
        job: "经理",
        lastMonth: 0,
        thisMonth: 0,
        total: 16.12,
        remark: '已离职',
      },
      {
        employee: "员工3",
        job: "经理",
        lastMonth: 17.2,
        thisMonth: 148.608,
        total: 19075.17,
        remark: '在职',
      },
    ],
  },
  {
    department: "销售C部",
    data: [
      {
        employee: "职员A",
        job: "经理",
        lastMonth: 4.62,
        thisMonth: 39.9168,
        total: 1812.23,
        remark: '实习',
      },
      {
        employee: "职员B",
        job: "经理",
        lastMonth: 7.911,
        thisMonth: 68.351,
        total: 7818.68,
        remark: '在职',
      },
    ],
  },
]);

2.书写模板:

 <div ref="wordRef">
    <div style="text-align:center;font-size:50px;font-weight:700;margin-bottom:50px;color:#e63e31;">2024年11月销售单
    </div>
    <div style="margin-bottom:30px;padding-bottom:30px;font-size:22px;font-weight:700;border-bottom:3px solid #e63e31;">
      <span style="text-align: left;">填报单位:XXX外贸公司</span>
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
      <span style="text-align: right;">单位:万元</span>
    </div>
    <table width="100%" border="1" style="border-collapse:collapse;">
      <tr>
        <td rowspan="2" style="height:28px;text-align:center;font-size:24px;font-weight:bold;background:#ccc;">部门</td>
        <td rowspan="2" style="height:28px;text-align:center;font-size:24px;font-weight:bold;background:#ccc;">员工</td>
        <td rowspan="2" style="height:28px;text-align:center;font-size:24px;font-weight:bold;background:#ccc;">职位</td>
        <td colspan="2" style="height:28px;text-align:center;font-size:24px;font-weight:bold;background:#ccc;">业绩</td>
        <td rowspan="2" style="height:28px;text-align:center;font-size:24px;font-weight:bold;background:#ccc;">全年销售总额
        </td>
        <td rowspan="2" width="10%"
          style="height:28px;text-align:center;font-size:24px;font-weight:bold;background:#ccc;">备注</td>
      </tr>
      <tr>
        <td style="height:28px;text-align:center;font-size:24px;font-weight:bold;background:#ccc;">上月</td>
        <td style="height:28px;text-align:center;font-size:24px;font-weight:bold;background:#ccc;">本月</td>
      </tr>
      <template v-for="(item) in tableDataList" :key="item">
        <tr>
          <td :rowspan="item.data.length" style="text-align:center">{{ item.department }}</td>
          <td style="text-align:center">{{ item.data[0].employee }}</td>
          <td style="text-align:center">{{ item.data[0].job }}</td>
          <td style="text-align:center">{{ item.data[0].lastMonth }}</td>
          <td style="text-align:center">{{ item.data[0].thisMonth }}</td>
          <td style="text-align:center">{{ item.data[0].total }}</td>
          <td style="text-align:center">{{ item.data[0].remark }}</td>
        </tr>
        <tr v-for="itemB in item.data.slice(1)">
          <td style="text-align:center">{{ itemB.employee }}</td>
          <td style="text-align:center">{{ itemB.job }}</td>
          <td style="text-align:center">{{ itemB.lastMonth }}</td>
          <td style="text-align:center">{{ itemB.thisMonth }}</td>
          <td style="text-align:center">{{ itemB.total }}</td>
          <td style="text-align:center">{{ itemB.remark }}</td>
        </tr>
      </template>
      <tr>
        <td colspan="7"></td>
      </tr>
    </table>
    <div style="margin-top: 50px;">
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
      领导签字
    </div>
    <div style="margin-top: 20px;">
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
      公司盖章
    </div>
    <div style="margin-top: 20px;">
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
      年&nbsp;&nbsp;&nbsp;月&nbsp;&nbsp;&nbsp;日
    </div>
  </div>

3.开始使用导出功能:

准备一个按钮

 <el-button type="primary" @click="exportWord">导出Word</el-button>

引入方法:

import { downloadWordWithHtmlString } from '../utils/word.js';

点击按钮的时候 导出word

// 导出Word文档
const exportWord = () => {
  downloadWordWithHtmlString(wordRef.value.innerHTML, '销售单');
};

五、完整代码:

import { saveAs } from "file-saver";
import { asBlob } from "html-docx-js-typescript";

export function downloadWordWithHtmlString(html, name) {
  let htmlString = `
  <!DOCTYPE html>
  <html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Document</title>
  </head>
  <body>
    ${html}
  </body>
  </html>
  `;
  asBlob(htmlString).then((data) => {
    saveAs(data, `${name}.docx`);
  });
}
<template>
  <el-button type="primary" @click="exportWord">导出Word</el-button>
  <div ref="wordRef">
    <div style="text-align:center;font-size:50px;font-weight:700;margin-bottom:50px;color:#e63e31;">2024年11月销售单
    </div>
    <div style="margin-bottom:30px;padding-bottom:30px;font-size:22px;font-weight:700;border-bottom:3px solid #e63e31;">
      <span style="text-align: left;">填报单位:XXX外贸公司</span>
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
      <span style="text-align: right;">单位:万元</span>
    </div>
    <table width="100%" border="1" style="border-collapse:collapse;">
      <tr>
        <td rowspan="2" style="height:28px;text-align:center;font-size:24px;font-weight:bold;background:#ccc;">部门</td>
        <td rowspan="2" style="height:28px;text-align:center;font-size:24px;font-weight:bold;background:#ccc;">员工</td>
        <td rowspan="2" style="height:28px;text-align:center;font-size:24px;font-weight:bold;background:#ccc;">职位</td>
        <td colspan="2" style="height:28px;text-align:center;font-size:24px;font-weight:bold;background:#ccc;">业绩</td>
        <td rowspan="2" style="height:28px;text-align:center;font-size:24px;font-weight:bold;background:#ccc;">全年销售总额
        </td>
        <td rowspan="2" width="10%"
          style="height:28px;text-align:center;font-size:24px;font-weight:bold;background:#ccc;">备注</td>
      </tr>
      <tr>
        <td style="height:28px;text-align:center;font-size:24px;font-weight:bold;background:#ccc;">上月</td>
        <td style="height:28px;text-align:center;font-size:24px;font-weight:bold;background:#ccc;">本月</td>
      </tr>
      <template v-for="(item) in tableDataList" :key="item">
        <tr>
          <td :rowspan="item.data.length" style="text-align:center">{{ item.department }}</td>
          <td style="text-align:center">{{ item.data[0].employee }}</td>
          <td style="text-align:center">{{ item.data[0].job }}</td>
          <td style="text-align:center">{{ item.data[0].lastMonth }}</td>
          <td style="text-align:center">{{ item.data[0].thisMonth }}</td>
          <td style="text-align:center">{{ item.data[0].total }}</td>
          <td style="text-align:center">{{ item.data[0].remark }}</td>
        </tr>
        <tr v-for="itemB in item.data.slice(1)">
          <td style="text-align:center">{{ itemB.employee }}</td>
          <td style="text-align:center">{{ itemB.job }}</td>
          <td style="text-align:center">{{ itemB.lastMonth }}</td>
          <td style="text-align:center">{{ itemB.thisMonth }}</td>
          <td style="text-align:center">{{ itemB.total }}</td>
          <td style="text-align:center">{{ itemB.remark }}</td>
        </tr>
      </template>
      <tr>
        <td colspan="7"></td>
      </tr>
    </table>
    <div style="margin-top: 50px;">
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
      领导签字
    </div>
    <div style="margin-top: 20px;">
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
      公司盖章
    </div>
    <div style="margin-top: 20px;">
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
      年&nbsp;&nbsp;&nbsp;月&nbsp;&nbsp;&nbsp;日
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import { downloadWordWithHtmlString } from '../utils/word.js';

let wordRef = ref(null);

const tableDataList = ref([
  {
    department: "销售A部",
    data: [
      {
        employee: "张三",
        job: "经理",
        lastMonth: 0.311,
        thisMonth: 2.687,
        total: 422.8,
        remark: '在职',
      },
      {
        employee: "李四",
        job: "经理",
        lastMonth: 3.704,
        thisMonth: 32.0026,
        total: 3250.7994,
        remark: '在职',
      },
      {
        employee: "王五",
        job: "经理",
        lastMonth: 1.588,
        thisMonth: 13.7203,
        total: 5133.14,
        remark: '实习',
      },
      {
        employee: "赵六",
        job: "经理",
        lastMonth: 0.83,
        thisMonth: 7.1712,
        total: 1680.8951,
        remark: '在职',
      },
    ],
  },
  {
    department: "销售B部",
    data: [
      {
        employee: "员工1",
        job: "经理",
        lastMonth: 6,
        thisMonth: 51.84,
        total: 13289.56,
        remark: '在职',
      },
      {
        employee: "员工2",
        job: "经理",
        lastMonth: 0,
        thisMonth: 0,
        total: 16.12,
        remark: '已离职',
      },
      {
        employee: "员工3",
        job: "经理",
        lastMonth: 17.2,
        thisMonth: 148.608,
        total: 19075.17,
        remark: '在职',
      },
    ],
  },
  {
    department: "销售C部",
    data: [
      {
        employee: "职员A",
        job: "经理",
        lastMonth: 4.62,
        thisMonth: 39.9168,
        total: 1812.23,
        remark: '实习',
      },
      {
        employee: "职员B",
        job: "经理",
        lastMonth: 7.911,
        thisMonth: 68.351,
        total: 7818.68,
        remark: '在职',
      },
    ],
  },
]);

// 导出Word文档
const exportWord = () => {
  downloadWordWithHtmlString(wordRef.value.innerHTML, '销售单');
};
</script>

六、注意事项:

你可以根据需要为表格添加样式,例如设置边框、背景色、字体大小等。

样式比较难调,我使用了行内样式,在标签上直接加style属性,样式单独拉出来不行,会没有效果,最好的方法就是写在行内样式,虽然比较冗余。

当时用了好几个库,大多都是不支持合并单元格,固定写死的模板,可控性差一些。这个还算是比较可控制的,毕竟是手撸table,反正是业务需求达到了。

具体情况还是看需求哦

七、其他的方法:

如果你有固定的导出模板,且不需要动态的合并单元格,只需要填充字段即可,那你可以参看这一篇文章:

vue项目:纯前端实现Word文档导出功能,一文搞定前端导出word文档,固定的word模板导出。-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值