一. 安装插件
npm install html2canvas --save
npm install jspdf --save
二. 封装方法 htmlToPdf.js
import html2canvas from 'html2canvas'
import JsPDF from 'jspdf'
/**
* @param ele 要生成 pdf 的DOM元素(容器)
* @param padfName PDF文件生成后的文件名字
* */
function downloadPDF(ele, pdfName){
let eleW = ele.offsetWidth
let eleH = ele.offsetHeight
let eleOffsetTop = ele.offsetTop
let eleOffsetLeft = ele.offsetLeft
var canvas = document.createElement("canvas")
var abs = 0
let win_in = document.documentElement.clientWidth || document.body.clientWidth
let win_out = window.innerWidth
if(win_out>win_in){
// abs = (win_o - win_i)/2
abs = (win_out - win_in)/2
// console.log(a, '新abs')
}
canvas.width = eleW * 2
canvas.height = eleH * 2
var context = canvas.getContext("2d")
context.scale(2, 2)
context.translate(-eleOffsetLeft -abs, -eleOffsetTop)
// 这里默认横向没有滚动条的情况,因为offset.left(),有无滚动条的时候存在差值,因此
// translate的时候,要把这个差值去掉
// 解决分页内容被切割问题
let pageHeightNum = canvas.width / 2 / 592.28 * 841.89
let lableListID = document.getElementsByClassName('target-node-item')
for (let i = 0
let multiple = Math.ceil((lableListID[i].offsetTop + lableListID[i].offsetHeight) / pageHeightNum)
if (isSplit(lableListID, i, multiple * pageHeightNum)) {
let divParent = lableListID[i].parentNode // 获取该div的父节点
let newNode = document.createElement('div')
newNode.className = 'seatDiv'
newNode.style.background = '#ffffff'
let _H = multiple * pageHeightNum - (lableListID[i].offsetTop + lableListID[i].offsetHeight)
newNode.style.height = _H + 50 + 'px'
let next = lableListID[i].nextSibling // 获取div的下一个兄弟节点
// 判断兄弟节点是否存在
if (next) {
// 存在则将新节点插入到div的下一个兄弟节点之前,即div之后
divParent.insertBefore(newNode, next)
} else {
// 不存在则直接添加到最后,appendChild默认添加到divParent的最后
divParent.appendChild(newNode)
}
}
}
html2canvas( ele, {
dpi: 300,
// allowTaint: true, //允许 canvas 污染, allowTaint参数要去掉,否则是无法通过toDataURL导出canvas数据的
useCORS:true //允许canvas画布内 可以跨域请求外部链接图片, 允许跨域请求。
} ).then( (canvas)=>{
var contentWidth = canvas.width
var contentHeight = canvas.height
//一页pdf显示html页面生成的canvas高度
var pageHeight = contentWidth / 592.28 * 841.89
//未生成pdf的html页面高度
var leftHeight = contentHeight
//页面偏移
var position = 0
//a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
var imgWidth = 595.28
var imgHeight = 595.28/contentWidth * contentHeight
var pageData = canvas.toDataURL('image/jpeg', 1.0)
var pdf = new JsPDF('', 'pt', 'a4')
//有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
//当内容未超过pdf一页显示的范围,无需分页
if (leftHeight < pageHeight) {
//在pdf.addImage(pageData, 'JPEG', 左,上,宽度,高度)设置在pdf中显示;
pdf.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight)
// pdf.addImage(pageData, 'JPEG', 20, 40, imgWidth, imgHeight)
} else { // 分页
while(leftHeight > 0) {
pdf.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)
leftHeight -= pageHeight
position -= 841.89
//避免添加空白页
if(leftHeight > 0) {
pdf.addPage()
}
}
}
let delArr = document.getElementsByClassName('seatDiv')
for(let i = delArr.length - 1
if(delArr[i] && delArr[i].parentElement) {
delArr[i].remove()
}
}
//可动态生成
pdf.save(pdfName)
})
}
function isSplit (nodes, index, pageHeight) {
if (nodes[index].offsetTop + nodes[index].offsetHeight < pageHeight && nodes[index + 1] && nodes[index + 1].offsetTop + nodes[index + 1].offsetHeight > pageHeight) {
return true
}
return false
}
export default {
downloadPDF
}
三. 页面调用
<div class="examDetail">
<el-row type="flex" justify="end" class="downloadBox">
<div class="btn" @click="handleDown">下载PDF报告</div>
</el-row>
<div class="testPaperWrap" id="pdfBox">
<div class="testPaperBox" v-for="(items, indexs) in paperArr" :key="indexs">
<div class="target-node-item testPaperTitle">
{{++indexs }}. {{items.topic}}
</div>
<div class="testPaperContent">
<div class="target-node-item figureBox">
<chart :options="items.chartOptions" autoresize style="width: 100%;height: 420px;"></chart>
</div>
<div class="target-node-item answerBox">
<el-table
header-cell-class-name="headerBox"
:data="items.data"
:span-method="objectSpanMethod"
border
style="width: 100%; margin-top: 20px">
<el-table-column
label="答案"
prop="answerCode"
width="180">
</el-table-column>
<el-table-column
prop="title"
label="选项">
<template slot-scope="scope">
<span>{{scope.row.fromCharCode}}. {{scope.row.answer}}</span>
</template>
</el-table-column>
<el-table-column
prop="selectedAnswerCount"
label="选择">
</el-table-column>
<el-table-column
label="占比">
<template slot-scope="scope">
<span>{{(scope.row.selectedAnswerCount / scope.row.topicSum * 100) | ratioFil}}%</span>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
<div class="testPaperBox">
<div class="target-node-item testPaperTitle">
分数分布图
</div>
<div class="target-node-item testPaperContent">
<div class="figureBox">
<chart :options="chartOptions" autoresize style="width: 100%;height: 420px;"></chart>
</div>
</div>
</div>
</div>
</div>
import htmlToPdf from '@/utils/htmlToPdf'
handleDown() {
htmlToPdf.downloadPDF( document.getElementById('pdfBox'), '下载pdf文件名');
},