2024.4.19 更新日志:有小伙伴私信我element-ui等ui插件等复杂样式无法转换生成,考虑到
html-docx-js本身不支持大多c3样式及标签,先提供解决方法将dom转成图片插入文档中,只需要用标签盒子 包裹住 你需要生成的dom模块,给标签盒子添加类目标识,配置项中传入 drawCanvas:[' .btn' ] ,就可以生成 具体效果图结尾有。
2024.3.11 更新日志 :允许使用class标签在html模版中使用 此前只支持行内标签修改样式 过于繁琐与不便 ,配置项中加入 className: "xxx", 当前模版的class类明即可识别使用
公司有业务需求 需要将前端页面一键导出word模版
后来找了半天只找到一个16年的插件html-docx-js(膜拜大神,但是已经无人维护了) ,使用后踩了许多坑,因为js版本兼容问题,运行都报错使用了with() 先版本不兼容,使用也比较繁琐,
最无法容忍的是如果是使用的在线图片还有跨域问题导致图片无法导出!!!
所以直接做了些优化处理 主要是对超时 错误图片处理 可以传入导出图片超时时间等等系列问题坑!!!已封装成傻瓜式一键导出插件,小伙伴可以放心食用,目前已投入公司项目中使用。
xh-htmlword
使用方法
npm install xh-htmlword
<template> <div class="export-box" style="width: 565pt"> <div id="main1"></div> <p style="text-align: center"> <span style=" font-family: 宋体; font-weight: bold; color: rgb(0, 0, 0); min-height: 16pt; font-size: 16pt; " >深水汴北配套管网运维日报表</span > </p> <table style="width: 565pt; border-collapse: collapse; border: 1px solid #dddddd" > <colgroup> <col style="width: 89.65pt" /> <col style="width: 44.05pt" /> <col style="width: 121.5pt" /> <col style="width: 103.85pt" /> <col style="width: 73.3pt" /> <col style="width: 106.3pt" /> </colgroup> <!-- 头部 --> <tr v-for="(item, index) in data.head" :key="index" style="border: 1px solid #cccccc; height: 25.5pt" > <td v-for="(item2, index) in item" :key="index" style="padding-left: 5.4pt; border: 1px solid #cccccc" :style="{ width: item2.width }" :colspan="index % 2 == 0 ? 2 : 1" > <span style=" font-weight: bold; color: #595959; font-size: 9pt; margin-right: 3pt; " > {{ item2.title }}</span > <span style="color: #595959; font-size: 9pt"> {{ item2.label }} </span> </td> </tr> <!-- 到岗人员 --> <tr style="border: 1px solid #cccccc; height: 25.5pt"> <td colspan="6" style="padding-left: 5.4pt; border: 1px solid #cccccc"> <span style=" font-weight: bold; color: #595959; font-size: 9pt; margin-right: 3pt; " > 到岗人员:</span > <span v-for="(item, index) in data.personnel" :key="index" style="color: #595959; font-size: 9pt" > <span v-if="index !== 0"> </span> <span>{{ item.title }}</span> <span> {{ item.label }} </span> </span> </td> </tr> <!-- 标准化执行情况 --> <tr style="border: 1px solid #cccccc; height: 25.5pt"> <td colspan="6" style="padding-left: 5.4pt; border: 1px solid #cccccc"> <span style=" font-weight: bold; color: #595959; font-size: 9pt; margin-right: 3pt; " > 标准化执行情况:</span > <span v-for="(item, index) in executionList" :key="index" style="color: #595959; font-size: 9pt" > <span v-if="index !== 0"> </span> <span>{{ data.execution == index ? "√" : "□" }}</span> <span> {{ item }} </span> </span> </td> </tr> <!-- 巡检记录 --> <tr style="border: 1px solid #cccccc; height: 36pt"> <td colspan="6" style=" text-align: center; border: 1px solid #cccccc; background-color: #f1f1f1; color: rgb(89, 89, 89); font-size: 14pt; letter-spacing: 1pt; " > 巡检记录 </td> </tr> <tr> <td colspan="6" style=" text-align: center; border: 1px solid #cccccc; background-color: #f1f1f1; color: rgb(89, 89, 89); font-size: 14pt; letter-spacing: 1pt; " > <img src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimage109.360doc.com%2FDownloadImg%2F2021%2F04%2F0713%2F219519055_1_20210407012803425&refer=http%3A%2F%2Fimage109.360doc.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1716081866&t=af941e4f60f743e1081f7cda8fcfb299" width="565pt" height="200pt" /> </td> </tr> </table> <div class="btn"> <el-progress :percentage="50" /> <el-progress :percentage="100" :format="format" /> <el-progress :percentage="100" status="success" /> <el-progress :percentage="100" status="warning" /> <el-progress :percentage="50" status="exception" /> <el-steps style="max-width: 600px" :active="0" finish-status="success"> <el-step title="Step 1" /> <el-step title="Step 2" /> <el-step title="Step 3" /> </el-steps> </div> </div> <button @click="handleExport">导出</button> </template> <script setup> import { onMounted, nextTick } from "vue"; import handleExportWord from "xh-htmlword"; // 标准化执行情况 const executionList = ["优秀", "良好", "中等", "差"]; // 巡检记录 const data = { head: [ [ { title: "作业日期:", label: "2024年01月25日", width: "150pt" }, { title: "填表人:", label: "吴宇、白阳", width: "110pt" }, { title: "运维单位:", label: "安徽中益达管道疏通有限公司", width: "200pt", }, { title: "天气:", label: "多云(24°C)", width: "120pt" }, ], [ { title: "现场负责人:", label: "吴宇", width: "150pt", }, { title: "手机号码:", label: "13112345678", width: "110pt", }, { title: "项目负责人:", label: "吴宇", width: "205pt", }, { title: "手机号码:", label: "13198765432", width: "120pt", }, ], ], personnel: [ { title: "安全员:", label: "1人", }, { title: "监护人员:", label: "1人", }, { title: "施工人员:", label: "3人", }, { title: "巡查人员:", label: "2人", }, { title: "潜水员:", label: "1人", }, { title: "有限空间作业人员:", label: "1人", }, ], execution: 1, }; const handleExport = () => { // dom:需要渲染的html父盒子标签 , 类型:string 例如 id/class // fileName:文件名称 类型:string // timeOut:设置导出图片加载 超时时间 默认值 5000 (5s) // callBack:导出成功回调函数 // options:配置项 类型:object 例如可传 {left:1440,right:1440} 控制页边距 // defultImg: 错误或者超时图片 默认图片地址 类型:string // className:当前组件的class属性名标识 类型:string 配置此项后可以在标签写入class样式 // drawCanvas:当当前页面有比较复杂的样式或组件(element-ui等) 页面中可以用样式标签将它包裹起来然后将标签 传入drawCanvas数组中 开启转换 handleExportWord({ dom: ".export-box", fileName: "托尔斯泰222", drawCanvas: [".btn"], }); }; </script>导出效果如下:
可以看到了element UI的组件也一起导出在最下方,项目是采用的vue3+vite,实际中vue2我试了也是没问题的,插件注意事项和使用方法可以去xh-htmlword查看,如果有使用疑惑或问题可以加我QQ:1031945252 交流联系,共同进步
注意:如果是使用的vue2版本,报了以下错误:
一定要在vue.config.js中加上配置项:
会转译node_modules中的包,解决报错!