注:本方法使用的是jspdf和html2canvas这两个插件,原理就是需要导出的部分,通过html2canvas的方法生成一个图片,然后使用jspdf导出成为一个真正的pdf文件。其中package.json文件中html2canvas的版本使用的是
"html2canvas": "^1.0.0-rc.7",
或者是这个版本
"html2canvas": "1.0.0-alpha.12",
下面的版本的好处是,textarea不用替换成为div元素,直接截图就可以了。
jspdf的本版是:
"jspdf": "^1.5.3",
导出PDF是一个很简单的功能了,但是近期遇到了的问题是当页面的内容比较多的时候,就导致了, 截图之后,滚动条下面的内容就看不到了。
首先看下导出pdf的封装的js:
// 导出页面为PDF格式
import html2canvas from "html2canvas"
import JSPDF from "jspdf"
export default {
install (Vue, options) {
Vue.prototype.ExportSavePdf = function (htmlTitle, currentTime) {
var element = document.getElementById("Etable")
html2canvas(element, {
logging: false
}).then(function (canvas) {
var pdf = new JSPDF("p", "mm", "a4") // A4纸,纵向
var ctx = canvas.getContext("2d")
var a4w = 170; var a4h = 257 // A4大小,210mm x 297mm,四边各保留20mm的边距,显示区域170x257
var imgHeight = Math.floor(a4h * canvas.width / a4w) // 按A4显示比例换算一页图像的像素高度
var renderedHeight = 0
while (renderedHeight < canvas.height) {
var page = document.createElement("canvas")
page.width = canvas.width
page.height = Math.min(imgHeight, canvas.height - renderedHeight)// 可能内容不足一页
// 用getImageData剪裁指定区域,并画到前面创建的canvas对象中
page.getContext("2d").putImageData(ctx.getImageData(0, renderedHeight, canvas.width, Math.min(imgHeight, canvas.height - renderedHeight)), 0, 0)
pdf.addImage(page.toDataURL("image/jpeg", 1.0), "JPEG", 10, 10, a4w, Math.min(a4h, a4w * page.height / page.width)) // 添加图像到页面,保留10mm边距
renderedHeight += imgHeight
if (renderedHeight < canvas.height) { pdf.addPage() }// 如果后面还有内容,添加一个空页
// delete page;
}
pdf.save(htmlTitle + currentTime)
})
}
}
}
其中var element = document.getElementById("Etable")是获取导出pdf的元素。这个例子是导出element的el-table的外面的div的id名。大体的结构是这样的
<div id="Etable">
<el-table
:data="tableData"
style="width: 100%"
height="100%"
:cell-class-name="borderLeft"
v-loading="loading"
id="EtableBody"
>
<template slot="empty">
<p>{{ dataText }}</p>
</template>
<el-table-column prop="name" width="30" label=""></el-table-column>
<el-table-column prop="deviceName" label="设备名称"></el-table-column>
<el-table-column prop="description" label="故障描述"></el-table-column>
<el-table-column prop="deviceClass" label="设备类别"></el-table-column>
<el-table-column prop="triggerTimes" width="78" label="触发次数">
<template slot-scope="scope">
<p>{{ addZero(scope) }}</p>
</template>
</el-table-column>
<el-table-column label="累计时间">
<template slot-scope="scope">
<!-- <p>{{scope.row.totalTime}}</p> -->
<p>{{ scope.row.totalTime | msToTimeOther }}</p>
</template>
</el-table-column>
<el-table-column prop="DetailCurveItem" width="700" label="24h分布图">
<template slot-scope="scope">
<my-echart :timeData="scope.row.distribution"></my-echart>
</template>
</el-table-column>
</el-table>
</div>
在外侧有一个按钮,用来导出PDF,调用的方法是exportPDFBtn。
大体就是,通过计算得到表格全体的内容的高度,然后截图,截图完成之后,重新恢复原来的高度,尽量让用户察觉不到。
具体的方法是这样的:
// 点击导出PDF按钮
exportPDFBtn(){
var dom = document.getElementById("EtableBody");
var headDom = dom.getElementsByClassName("el-table__header-wrapper")[0];
var headerHeight = headDom.offsetHeight;
var bodyDom = dom.getElementsByClassName("el-table__body")[0];
var bodyHeight = bodyDom.offsetHeight;
var noScrollHeight = headerHeight + bodyHeight + 30;
var Etable = document.getElementById("Etable");
Etable.style.height = noScrollHeight + "px";
this.$message({
message: "导出成功,请稍后",
type: "success",
});
setTimeout(()=>{
this.ExportSavePdf('故障分布', this.dataValueSimple);
}, 200)
setTimeout(()=>{
Etable.style.height = "100%";
}, 1000)
}
如果是页面的话,其实是同理的。计算出滚动的距离,然后在截图的时候,把需要截图的元素的父元素高度设置为截图元素的高度,截图完成之后,重新把截图元素的父元素设置为原来的高度。