前言:
記錄一下最近的一個需求,產品需要列印表單憑證,需要實作將選中頁面的元素或者是組件匯出為PDF,方便列印
使用到的JS庫:html2canvas(截取頁面生成canvas),jsPDF(使用JS生成PDF)
下面我針對該需求實作一個簡單的Demo,并且分享一下遇到的問題
首先,我選擇了懶加載的案例作為測驗物件,因為圖片可以檢測截圖效果,并且有滾動加載長頁面
我們把整個demo分為兩部分,分別是使用上述兩個插件實作基本功能
使用html2canvas截屏生成canvas
let printEle, //截圖按鈕
pdfEle, //待截取標簽
canvasBox //canvas顯示區域
(function init(_win, _dom) {
printEle = _dom.querySelector('#printEle')
pdfEle = _dom.querySelector('#pdfEle')
canvasBox = _dom.querySelector('#canvasBox')
printEle.addEventListener('click', clickHandler) //點擊按鈕生成截屏
})(window, document)
async function clickHandler(e) {
if (canvasBox.children.length) return //若canvas顯示區域已經有標簽則退出
const canvas = await html2canvas(pdfEle, { //截取標簽轉換為canvas
background: '#FFFFFF',
})
pdfEle.hidden = true //隱藏之前的元素,更好對比
canvasBox.appendChild(canvas) //顯示效果
}
原圖 截圖


二者清晰度差距看上去好像不是很大,但是放大圖片后會發現截圖結果很模糊

在網上找了一些方法,但是都不盡人意,用到最多的方法是修改配置項,在html2canvas異步函式中新增dpi和scale,但是在原始碼里搜索dpi欄位并未找到,不知道是不是官方取消了,于是我找到另一種方法對canvas進行縮放,緩解失真
好在html2canvas提供了自定義canvas的屬性,用戶可以自定義canvas屬性達到效果![]()
于是我們寫一個新建canvas方法,對其進行縮放
function createCanvas(target) {
//target是待截取的標簽,我們通過target生成對應大小的canvas
let canvas = document.createElement("canvas");
let context = canvas.getContext("2d")
canvas.width = target.offsetWidth * scale; // 畫布實際寬度
canvas.height = target.offsetHeight * scale; // 畫布實際高度
canvas.style.width = target.offsetWidth + 'px' // 瀏覽器上顯示的寬度
canvas.style.height = target.offsetHeight + 'px' //瀏覽器上顯示的高度
context.scale(scale, scale); //等比縮放
return canvas
}
在新建截圖時呼叫
const canvas = await html2canvas(pdfEle, { //截取標簽轉換為canvas
canvas: createCanvas(pdfEle),
background: '#FFFFFF',
})
效果是這樣的,清晰度的問題已經解決,但是列印canvas時會有Y軸上的距離偏移,由于本人對canvas不是很熟練,猜測是由于按鈕的高度影響的,因為修改按鈕高度(不超過待截屏的元素高度),偏移量相對應也發生同樣長度的偏移
此時我們使用getBoundingClientRect()的方法獲取待截取標簽的位置相對于瀏覽器可視范圍的偏移量,然后通過canvas的translate方式取反位移,即可解決該問題
function createCanvas(target) {
//target是待截取的標簽,我們通過target生成對應大小的canvas
let canvas = document.createElement("canvas");
let context = canvas.getContext("2d")
let clientRect = target.getBoundingClientRect()// 獲取標簽相對可視區域的偏移量
canvas.width = target.offsetWidth * scale; // 畫布實際寬度
canvas.height = target.offsetHeight * scale; // 畫布實際高度
canvas.style.width = target.offsetWidth + 'px' // 瀏覽器上顯示的寬度
canvas.style.height = target.offsetHeight + 'px' //瀏覽器上顯示的高度
context.scale(scale, scale); //等比縮放
context.translate(-clientRect.left, -clientRect.top);//通過translate取反位移
return canvas
}
效果如下,生成的圖片要比之前的清晰很多,我們還可以通過修改scale來控制圖片清晰度

實作了將HTML頁面通過canvas顯示后,下一步我們就需要使用jsPDF生成PDF檔案并下載了
function downloadPdf(canvas) { //將canvas變成PDF并下載
const size = [canvas.width / scale, canvas.height / scale] //pdf真實寬高
//第一個引數表示橫向與縱向,具體可看檔案,我這里做了一個適配,寬比高長則是橫向反之則是縱向
const doc = new jsPDF(size[0] / size[1] > 1 ? 'l' : 'p', 'px', size)
doc.addImage(canvas.toDataURL('image/jpeg', 1.0), 'JPEG', 0, 0, ...size) //將canvas轉換為圖片并添加到jsPDF中
doc.save("test.pdf"); //保存PDF
}
我們試試長截屏
最后附上完整代碼,界面和樣式可以直接在倉庫中找到
const {
jsPDF
} = jspdf, scale = 2 //縮放程度,清晰度,越大越清晰,圖片也越大
let printEle, //截圖按鈕
pdfEle, //待截取標簽
canvasBox //canvas顯示區域
(function init(_dom) {
printEle = _dom.querySelector('#printEle')
pdfEle = _dom.querySelector('#pdfEle')
canvasBox = _dom.querySelector('#canvasBox')
printEle.addEventListener('click', clickHandler) //點擊按鈕生成截屏
})(document)
async function clickHandler(e) {
if (canvasBox.children.length) return //若canvas顯示區域已經有標簽則退出
const canvas = await html2canvas(pdfEle, { //截取標簽轉換為canvas
canvas: createCanvas(pdfEle),
background: '#FFFFFF'
})
downloadPdf(canvas)
pdfEle.hidden = true //隱藏之前的元素,更好對比
canvasBox.appendChild(canvas) //顯示效果
}
function downloadPdf(canvas) { //將canvas變成PDF并下載
const size = [canvas.width / scale, canvas.height / scale] //pdf真實寬高
//第一個引數表示橫向與縱向,具體可看檔案,我這里做了一個適配,寬比高長則是橫向反之則是縱向
const doc = new jsPDF(size[0] / size[1] > 1 ? 'l' : 'p', 'px', size)
doc.addImage(canvas.toDataURL('image/jpeg', 1.0), 'JPEG', 0, 0, ...size) //將canvas轉換為圖片并添加到jsPDF中
doc.save("test.pdf"); //保存PDF
}
function createCanvas(target) { //target是待截取的標簽,我們通過target生成對應大小的canvas
let canvas = document.createElement("canvas");
let context = canvas.getContext("2d")
let clientRect = target.getBoundingClientRect() // 獲取標簽相對可視區域的偏移量
canvas.width = target.offsetWidth * scale; // 畫布實際寬度
canvas.height = target.offsetHeight * scale; // 畫布實際高度
canvas.style.width = target.offsetWidth + 'px' // 瀏覽器上顯示的寬度
canvas.style.height = target.offsetHeight + 'px' //瀏覽器上顯示的高度
context.scale(scale, scale); //等比縮放
context.translate(-clientRect.left, -clientRect.top); //通過translate取反位移
return canvas
}
希望這篇文章對你有幫助,歡迎提出建議與優化,謝謝!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/281280.html
標籤:其他
上一篇:JavaScript BOM操作
