Vue - 将页面内容下载为 pdf 格式文件(html2canvas + jspdf)
一. 安装所需依赖
npm install html2canvas --save
npm install jspdf --save
二. htmlToPdfNew.js 核心文件
import jsPDF from "jspdf" ;
import html2canvas from "html2canvas" ;
class PdfLoader {
constructor ( ele, pdfFileName, splitClassName ) {
this . ele = ele;
this . pdfFileName = pdfFileName;
this . splitClassName = splitClassName;
this . A4_WIDTH = 595 ;
this . A4_HEIGHT = 842 ;
}
async getPDF ( ) {
let ele = this . ele;
let pdfFileName = this . pdfFileName;
let eleW = ele. offsetWidth;
let eleH = ele. scrollHeight;
let eleOffsetTop = ele. offsetTop;
let eleOffsetLeft = ele. offsetLeft;
let canvas = document. createElement ( "canvas" ) ;
let abs = 0 ;
let win_in =
document. documentElement. clientWidth || document. body. clientWidth;
let win_out = window. innerWidth;
if ( win_out > win_in) {
abs = ( win_out - win_in) / 2 ;
}
canvas. width = eleW * 2 ;
canvas. height = eleH * 2 ;
let context = canvas. getContext ( "2d" ) ;
context. scale ( 3 , 3 ) ;
context. translate ( - eleOffsetLeft - abs, - eleOffsetTop) ;
html2canvas ( ele, {
useCORS : true ,
} ) . then ( async ( canvas ) => {
let contentWidth = canvas. width;
let contentHeight = canvas. height;
let pageHeight = ( contentWidth / this . A4_WIDTH ) * this . A4_HEIGHT ;
let leftHeight = contentHeight;
let position = 30 ;
let imgWidth = this . A4_WIDTH - 60 ;
let imgHeight = ( this . A4_WIDTH / contentWidth) * contentHeight;
let pageData = canvas. toDataURL ( "image/jpeg" , 1.0 ) ;
let pdf = jsPDF ( "" , "pt" , "a4" ) ;
if ( leftHeight < pageHeight) {
pdf. addImage ( pageData, "JPEG" , 30 , 20 , imgWidth, imgHeight) ;
} else {
while ( leftHeight > 0 ) {
pdf. addImage ( pageData, "JPEG" , 30 , position, imgWidth, imgHeight) ;
leftHeight -= pageHeight;
position -= this . A4_HEIGHT ;
if ( leftHeight > 0 ) {
pdf. addPage ( ) ;
}
}
}
pdf. save ( pdfFileName + ".pdf" , { returnPromise : true } ) . then ( ( ) => {
let doms = document. querySelectorAll ( ".emptyDiv" ) ;
for ( let i = 0 ; i < doms. length; i++ ) {
doms[ i] . remove ( ) ;
}
} ) ;
this . ele. style. height = "" ;
} ) ;
}
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 ;
}
async outPutPdfFn ( pdfFileName ) {
return new Promise ( ( resolve, reject ) => {
this . ele. style. height = "initial" ;
pdfFileName ? ( this . pdfFileName = pdfFileName) : null ;
let target = this . ele;
let pageHeight = ( target. scrollWidth / this . A4_WIDTH ) * this . A4_HEIGHT ;
let domList = document. getElementsByClassName ( this . splitClassName) ;
let pageNum = 1 ;
let eleBounding = this . ele. getBoundingClientRect ( ) ;
for ( let i = 0 ; i < domList. length; i++ ) {
let node = domList[ i] ;
let bound = node. getBoundingClientRect ( ) ;
let offset2Ele = bound. top - eleBounding. top;
let currentPage = Math. ceil (
( bound. bottom - eleBounding. top) / pageHeight
) ;
if ( pageNum < currentPage) {
pageNum++ ;
let divParent = domList[ i] . parentNode;
let newNode = document. createElement ( "div" ) ;
newNode. className = "emptyDiv" ;
newNode. style. background = "white" ;
newNode. style. height =
pageHeight * ( pageNum - 1 ) - offset2Ele + 30 + "px" ;
newNode. style. width = "100%" ;
let next = domList[ i] . nextSibling;
if ( next) {
divParent. insertBefore ( newNode, node) ;
} else {
divParent. appendChild ( newNode) ;
}
}
}
} ) ;
}
}
export default PdfLoader;
三. 组件使用方法
引入 htmlToPdfNew.js
核心文件import PdfLoader from "./htmlToPdfNew.js" ;
dom 设置
< button @click = " downLoadPdf" > 下载</ button>
< div id = " pdfContainer" > </ div>
下载事件方法downLoadPdf ( ) {
let ele = document. getElementById ( "pdfContainer" ) ;
let pdf = new PdfLoader ( ele, "测试" , "itemClass" ) ;
pdf. getPDF ( ) ;
} ,
四. 组件使用实例
< template>
< div class = " home" >
< button @click = " downLoadPdf" > 下载</ button>
< div id = " pdfContainer" class = " pdfContainer" >
< div class = " title" > PDF 标题</ div>
< div class = " itemClass" > </ div>
< div class = " info" >
< div class = " text1" > 君不见黄河之水天上来,奔流到海不复回。</ div>
< div class = " text2" > 君不见高堂明镜悲白发,朝如青丝暮成雪。</ div>
</ div>
</ div>
</ div>
</ template>
< script>
import PdfLoader from "./htmlToPdfNew.js" ;
export default {
methods : {
downLoadPdf ( ) {
let ele = document. getElementById ( "pdfContainer" ) ;
let pdf = new PdfLoader ( ele, "测试" , "itemClass" ) ;
pdf. getPDF ( ) ;
} ,
} ,
} ;
</ script>
< style scoped lang = " scss" >
.home {
width : 100%;
height : 100%;
.pdfContainer {
width : 800px;
padding : 10px 20px;
border : 1px solid #e2e2e2;
box-sizing : border-box;
text-align : center;
.title {
text-align : center;
font-weight : bold;
padding-bottom : 10px;
}
.info {
line-height : 35px;
.text1 {
color : rgb ( 0, 170, 255) ;
}
.text2 {
color : rgb ( 255, 119, 0) ;
}
}
}
}
</ style>