可以解决html2canvas的一些常见的坑,分页截断,页面太长导致的空白,生成的pdf无法预览
function previewPDF(ele, pdfName, title) {
//title为传过来的标题,ele为需打印区域
if (title) {
ele.insertAdjacentHTML(
"afterbegin",
`<div id='titlebox' style="text-align:center;margin-bottom: 20px;">${title}</div>`
);
}
document.documentElement.scrollTop = 0; //将滚动条置顶,以免pdf留白
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 * 1; // 将画布宽&&高放大两倍
canvas.height = eleH * 1;
let A4_WIDTH = 25.4;
let A4_HEIGHT = 14.288;
//从这里开始是进行分页的判断,避免页面上的元素在生成pdf时被截断
//但如果页面上的表格是el-table时offsetTop获取的高度不对
//offsetTop获取的是到有定位的父元素的高度
//所以el-table__row获取的高度是到表头底部的距离
//如果表格之上再没有元素可以加上表头的高度进行循环判断,否则只能用原生的table
//我没写成功所以手动调整了表格上面盒子的高度
let pageHeight = (ele.offsetWidth / A4_WIDTH) * A4_HEIGHT;
// 将所有不允许被截断的元素进行处理
let nodes = document.getElementById("printBox");
// let wholeNodes = document.getElementsByClassName("el-table__row");
// for (let i = 0; i < wholeNodes.length; i++) {
// //1、 判断当前的不可分页元素是否在两页显示
// const topPageNum = Math.ceil(wholeNodes[i].offsetTop / pageHeight);
// const bottomPageNum = Math.ceil(
// (wholeNodes[i].offsetTop + wholeNodes[i].offsetHeight) / pageHeight
// );
// if (topPageNum !== bottomPageNum) {
// //说明该dom会被截断
// // 2、插入空白块使被截断元素下移
// let divParent = wholeNodes[i].parentNode;
// let newBlock = document.createElement("div");
// newBlock.className = "emptyDiv";
// newBlock.style.background = "#fff";
// // 3、计算插入空白块的高度 可以适当流出空间使得内容太靠边,根据自己需求而定
// let _H = topPageNum * pageHeight - wholeNodes[i].offsetTop;
// newBlock.style.height = _H + 30 + "px";
// divParent.insertBefore(newBlock, wholeNodes[i]);
// }
// }
var context = canvas.getContext("2d");
context.scale(2, 2);
context.translate(-eleOffsetLeft - abs, -eleOffsetTop);
// 这里默认横向没有滚动条的情况,因为offset.left(),有无滚动条的时候存在差值,因此
// translate的时候,要把这个差值去掉
// html2canvas(element).then( (canvas)=>{ //报错
var modal = document.querySelector(".el-drawer__body");
html2canvas(ele, {
windowHeight: modal.scrollHeight, //获取y方向页面包含滚动条的高度
width: ele.offsetWidth,
height: ele.clientHeight,
y: ele.offsetTop,//设置这三个数据是解决需要截取的内容过长有滚动条并且是在弹框中
scale: window.devicePixelRatio * 2, // 增加清晰度
dpi: 360,
// allowTaint: true, //允许 canvas 污染, allowTaint参数要去掉,否则是无法通过toDataURL导出canvas数据的
useCORS: true, //允许canvas画布内 可以跨域请求外部链接图片, 允许跨域请求。
}).then((canvas) => {
//dom 已经转换为canvas 对象,可以将插入的空白块删除了
let emptyDivs = document.querySelectorAll(".emptyDiv");
for (let i = 0; i < emptyDivs.length; i++) {
emptyDivs[i].parentNode.removeChild(emptyDivs[i]);
}
//去掉标题
let title = document.querySelector("#titlebox");
title.parentNode.removeChild(title);
var contentWidth = canvas.width;
var contentHeight = canvas.height;
//一页pdf显示html页面生成的canvas高度;
var pageHeight = (contentWidth / 25.4) * 14.288;
//未生成pdf的html页面高度
var leftHeight = contentHeight;
//页面偏移
var position = 0;
//a4纸的尺寸[841,594],html页面生成的canvas在pdf中图片的宽高
var imgWidth = 25.4;
var imgHeight = (25.4 / contentWidth) * contentHeight;
//生成页面截图的图片
var pageData = canvas.toDataURL("image/jpeg", 1.0);
//设置了宽高修复了滚动条,也没有避免图片太大,生成pdf直接在浏览器预览时是空白,导出是正确的,
//在浏览器预览导出的pdf也不是空白,为了解决直接预览,需要将base64的图片放在img标签上就可以预览
//同时我们的需求是需要下载打印,所以我单独写了一个html页面,开启一个新窗口
let str = `<!DOCTYPE html>
<html>
<head>
<title>审批单预览</title>
</head>
<body>
<div style='text-align: right;margin-top:20px;margin-right: 20px;' class='hidden-print'>
<button class='button' οnclick='download("${pageData}")'>下载</button>
<button class='button' οnclick='beforePrint();window.print();afterPrint();'>打印</button>
</div>
<img style='width:98%;padding: 20px;margin-top:0' src='${pageData}' />
</body>
<style>
.button{
width:60px;
height:30px;
color: #FFF;
background-color: #409EFF;
border:none;
border-radius: 3px;
cursor: pointer
}
</style>
<script>
//去掉body和html的外边距可以避免调用浏览器打印时多生成空白页面
let margin = "0";
let padding = "0";
let height = "100%";
let html = document.getElementsByTagName("html")[0];
html.style.margin = margin;
html.style.padding = padding;
html.style.height = height;
let body = document.getElementsByTagName("body")[0];
body.style.margin = margin;
body.style.padding = padding;
body.style.height = height;
//下载
function download(pageData) {
//创建a标签
let bqa = document.createElement("a");
//给a标签的href属性赋值
bqa.href=pageData
//给a标签的download属性赋值,表示下载的文件名
bqa.setAttribute("download", "审批单");
//调用a标签的点击事件
bqa.click();
//移除a标签
bqa.remove();
}
//打印之前隐藏不想打印出来的信息
function beforePrint(){
document.getElementsByClassName("hidden-print")[0].style.display='none'
}
//打印之后将隐藏掉的信息再显示出来
function afterPrint(){
document.getElementsByClassName("hidden-print")[0].style.display='block';
}
</script>
</html>`;
let newOpen = window.open("", "审批单预览");
//不需要打印下载只需预览过大图片可以直接创建img标签,并新开窗口打开
// let creatDom = newOpen.document.createElement("img");
// creatDom.src = pageData;
// creatDom.style.width = "100%";
// newOpen.document.body.appendChild(creatDom);
newOpen.document.write(str);
//如果没有上面的需求只需要分页,可以用下面的代码进行导出和预览
//l:横向, p:纵向;单位: in:英寸,mm毫米;画布大小:a3,a4,leter,[](当内容为数组时,为自定义大小)
// var pdf = new JsPDF("l", "cm", [25.4, 14.288]);
// // var pdf = new JsPDF('l', 'pt', 'legal');
// //有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(594)
// //当内容未超过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 -= 14.288;
// //避免添加空白页
// if (leftHeight > 0) {
// pdf.addPage();
// }
// }
// }
//可动态生成
// pdf.save(pdfName); //导出pdf
// pdf.output("dataurlnewwindow"); //预览pdf
});
}