前端实现报表批量导出(html-to-image+jspdf)
在vue应用中通过vue-print-nb实现单个文件打印,通过html-to-image+jspdf实现页面批量下载
·
前端实现报表批量导出(html-to-image+jspdf)
1.问题描述
起初只是一个简单的报表预览和打印功能,这里使用的是vue-print-nb
插件来实现打印部分页面的功能。选择报表点击查看,然后根据报表的id去获取报表的详细数据,渲染在页面。所以报表只能查看一个下载一个,现在提了一个新的需求需要批量下载这些报表,不用一个一个点。
2.单个报表下载的实现方式
实现起来很轻松,甚至不用写js代码
- 第一步在mian.js导入打印插件
/* 第一步在mian.js导入打印插件*/
import Print from 'vue-print-nb'
Vue.use(Print);
- 给打印事件触发按钮添加自定义指令
v-print
,并赋值要打印区域的id
<!-- 打印事件触发按钮 -->
<el-button type="text" v-print="'#printDom'" icon="el-icon-printer">打印</el-button>
<!-- 要打印的区域 -->
<div id="printDom" style="padding: 20px;">
数据展示区域
</div>
3.批量下载
批量下载需要解决的问题:
- 如何实现多个文件下载
- 如何控制页面获取到了数据并完成了渲染再下载页面,避免下载空白的文件
- 怎么判断文件是否下载完成,清空页面dom元素。
第一个问题解决:
通过v-for
循环渲染
将通过el-table
的selection-change
选中方法获取到需要下载的报表的ID数组
<!-- 批量下载结算单 -->
<div :id="'patchPrintDom' + index" v-for="(patchInfo, index) in patchInfoList" :key="index">
报表组件
<statement :id="patchInfo.id"></statement >
</div>
第二个问题解决:
在报表组件内通过emit
在触发,父组件的打印事件。在接口数据返回之后,并给data()中属性赋值之后再emit,因为是下载是获取dom元素,还要考虑到页面更新的不及时所以还需要调用$nextTick()
方法来获取页面更新之后的dom
//statement组件内部异步方法
async getDetailData(){
const params={
//...
}
try {
const res = await Promise.all([saleList(params), saleDetail(params)])
//赋值操作
this.$nextTick(() => {
setTimeout(() => {
//延时触发emit
this.$emit('loading', false)
}, 1000)
})
} finally {
}
}
在组件上加loading事件,调用handfill方法
<!-- 批量下载结算单 -->
<div :id="'patchPrintDom' + index" name="patchInfo.name" v-for="(patchInfo, index) in patchInfoList" :key="index">
报表组件
<statement :id="patchInfo.id" @loading="handlefill(index)"></statement >
</div>
handfill方法的实现:将dom元素转为图片,再将图片添加进pdf
handlefill (index) {
const dom = document.getElementById('patchPrintDom' + index)
this.patchInfoList[index].visiable = false
// 下载dom为图片
htmlToImage.toPng(dom).then(url => {
const img = new Image()
img.src = url
img.onload = function () {
//创建一个pdf 第一个参数是横向/纵向 第二个参数是单位
const pdf = new jsPDF('1', 'pt', [img.width, img.height])
//addImage方法添加图片
pdf.addImage(this, 'PNG', 0, 0, img.width, img.height, '', 'FAST')
//如果图片高度超过pdf最大高度,就再加一页
if(img.height>pdf.internal.pageSize.getHeight()){
pdf.addPage()
pdf.addImage(this, 'PNG', 0, -(pdf.internal.pageSize.getHeight()-10), img.width, img.height, '', 'FAST')
}
//保存的时候取name属性的值作为文件名
pdf.save(dom.getAttribute('name') + '.pdf')
}
})
//判断是否全部下载完成
let all = this.patchInfoList.every(e => {
return !e.visiable
})
//全部下载完成
if (all) {
this.$message.success('下载完成。')
setTimeout(() => {
this.patchInfoList = []
}, 1000)
// this.patchInfoList = []
}
}
更多推荐
已为社区贡献5条内容
所有评论(0)