一、先看效果:
纯前端手撸格式,只需要有数据就行。
二、使用的库:
"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>
<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;">
领导签字
</div>
<div style="margin-top: 20px;">
公司盖章
</div>
<div style="margin-top: 20px;">
年 月 日
</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>
<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;">
领导签字
</div>
<div style="margin-top: 20px;">
公司盖章
</div>
<div style="margin-top: 20px;">
年 月 日
</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,反正是业务需求达到了。
具体情况还是看需求哦
七、其他的方法:
如果你有固定的导出模板,且不需要动态的合并单元格,只需要填充字段即可,那你可以参看这一篇文章: