前言
最近在項目中,有一個導出pdf功能,需要純前端來實現,調研了多種pdf導出方式,最終決定使用html2canvas+jsPDF來實現需求。
本文就簡單介紹一下html2canvas+jsPDF導出pdf的實現,網上大部分實現導出pdf都是以分頁為主的,本文還將附上不分頁導出pdf的實現方法。(只附js代碼)
html2canvas+jsPDF導出pdf原理:通過html2canvas將遍歷頁面元素,並渲染生成canvas,然后將canvas圖片格式添加到jsPDF實例,生成pdf。
安裝:
npm install html2canvas --save
npm install jsPDF --save
配置:
main.js文件里面配置(引入、掛載)
import html2canvas from 'html2canvas'
import jsPDF from 'jsPDF '
Vue.prototype.html2canvas = html2canvas
Vue.prototype.jsPDF = jsPDF
或者--------------------------------------------------------------------------------
index.html頁面直接引入js文件:
<script src="https://cdn.bootcss.com/html2canvas/0.5.0-beta4/html2canvas.js"></script>
<script src="https://cdn.bootcss.com/jspdf/1.3.4/jspdf.debug.js"></script>
導出pdf按a4紙大小分頁處理:// 下載pdf完整方法
downPdf () {
注意:生成的pdf只有頁面窗口可見的區域,有滾動條的下面沒有生成出來(要注意這里是一個坑)
坑:如果截取是body的這個層級,而剛好body設置了overflow: hidden;那超出的部分是永遠截取不到的,因為這個節點的dom高就是窗口可見的高度,並不包含滾動條多出來的部分。
解決辦法:只需要在導出之前將overflow:auto設置成visible(默認即可);
導出pdf后再設置回去。
// 導出之前將dom的overflow:auto設置成visible
this.$('#boardPdf').css({'overflow-y': 'visible', 'height': 'auto'})
this.$('#app').css({'overflow-y': 'visible', 'height': 'auto'})
this.$('body').css({'overflow-y': 'visible', 'height': 'auto'})
// eslint-disable-next-line
html2canvas(document.querySelector('#boardPdf'), {
scale: 2,
onrendered: function (canvas) {
var contentWidth = canvas.width
var contentHeight = canvas.height
// 一頁pdf顯示html頁面生成的canvas高度;
var pageHeight = contentWidth / 592.28 * 841.89
// 未生成pdf的html頁面高度
var leftHeight = contentHeight
// pdf頁面偏移
var position = 0
// a4紙的尺寸[595.28,841.89],html頁面生成的canvas在pdf中圖片的寬高
var imgWidth = 595.28
var imgHeight = 592.28 / contentWidth * contentHeight
var pageData = canvas.toDataURL('image/jpeg', 1.0)
// eslint-disable-next-line
var pdf = new jsPDF('', 'pt', 'a4')
// 有兩個高度需要區分,一個是html頁面的實際高度,和生成pdf的頁面高度(841.89)
// 當內容未超過pdf一頁顯示的范圍,無需分頁
if (leftHeight < pageHeight) {
pdf.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight)
} else {
while (leftHeight > 0) {
pdf.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)
leftHeight -= pageHeight
position -= 841.89
// 避免添加空白頁
if (leftHeight > 0) {
pdf.addPage()
}
}
}
// 導出pdf文件命名
pdf.save('report_pdf_' + new Date().getTime() + '.pdf')
},
background: '#0B1A48'
})
// 導出pdf后,將dom原本的屬性設置回去
this.$('#boardPdf').css({'overflow-y': 'auto', 'height': '100%'})
this.$('#app').css({'overflow-y': 'auto', 'height': '100%'})
this.$('body').css({'overflow-y': 'auto', 'height': '100%'})
}
導出pdf自適應大小不分頁處理:
// 下載pdf完整方法
downPdf () {
// 生成的pdf只有頁面窗口可見的區域,有滾動條的下面沒有生成出來,需在生成PDF前,改overflow屬性auto為visible
this.$('#boardPdf').css({'overflow-y': 'visible', 'height': 'auto'})
this.$('#app').css({'overflow-y': 'visible', 'height': 'auto'})
this.$('body').css({'overflow-y': 'visible', 'height': 'auto'})
// 獲取dom高度、寬度
var shareContent = document.querySelector('#boardPdf')
var width = shareContent.offsetWidth / 4
var height = shareContent.offsetHeight / 4
let _this = this
// eslint-disable-next-line
html2canvas(document.querySelector('#boardPdf'), {
onrendered: function (canvas) {
var context = canvas.getContext('2d')
context.mozImageSmoothingEnabled = false
context.webkitImageSmoothingEnabled = false
context.msImageSmoothingEnabled = false
context.imageSmoothingEnabled = false
var pageData = canvas.toDataURL('image/jpeg', 1.0)
var img = new Image()
img.src = pageData
img.onload = function () {
// 獲取dom高度、寬度
img.width = img.width / 2
img.height = img.height / 2
img.style.transform = 'scale(0.5)'
if (width > height) {
// 此可以根據打印的大小進行自動調節
// eslint-disable-next-line
var pdf = new jsPDF('l', 'mm', [
width * 0.505,
height * 0.545
])
} else {
// eslint-disable-next-line
var pdf = new jsPDF('p', 'mm', [
width * 0.505,
height * 0.545
])
}
pdf.addImage(
pageData,
'jpeg',
0,
0,
width * 0.505,
height * 0.545
)
pdf.save(_this.boardNameTitle + '.pdf')
}
},
background: '#0B1A48'
})
// 導出pdf后,將dom原本屬性設置回去
this.$('#boardPdf').css({'overflow-y': 'auto', 'height': '100%'})
this.$('#app').css({'overflow-y': 'auto', 'height': '100%'})
this.$('body').css({'overflow-y': 'auto', 'height': '100%'})
}