最近遇到了需要把網(wǎng)頁下載為圖片和打印為PDF的需求坚芜,特此整理凶掰。
一吴汪、借助瀏覽器
一般瀏覽器都自帶PDF打印功能:
至于保存為圖片钞楼,有很多瀏覽器插件(比如screenshot沽翔、花瓣)等,都可以將網(wǎng)頁保存為圖片窿凤。
缺點:
- 網(wǎng)頁中的圖標(biāo)仅偎、背景等可能無法打印成PDF,因此效果不好雳殊;
- 很多時候我們想打印網(wǎng)頁的某一部分(而不是整個網(wǎng)頁)橘沥,因此可定制性較差。
因此我們需要結(jié)合js來實現(xiàn)以上需求夯秃。
二座咆、用js
1、js + 瀏覽器打印功能
(1)打印整個頁面:
window.print()
(2)打印頁面中的指定元素:
一般來說仓洼,我們會用CSS將不需要打印的元素隱藏掉介陶,這樣body中實際上就只剩我們希望打印的頁面部分:
@media print {
body * {
visibility: hidden;
}
#printArea, #printArea * {
visibility: visible;
}
#printArea {
position: fixed;
left: 0;
top: 0;
right:0;
bottom:0;
}
}
再調(diào)用window.print()
即可。
但是測試后發(fā)現(xiàn)色建,這種方法還是存在問題:如果要打印的元素較長(大于一屏)哺呜,大于一屏的部分不會被打印。
我們再換一種思路:
//打印區(qū)域的內(nèi)容
var printContents = document.getElementById('printArea').innerHTML
//頁面的所有內(nèi)容
var originalContents = document.body.innerHTML
document.body.innerHTML = printContents
window.print()
document.body.innerHTML = originalContents
//直接恢復(fù)頁面可能會造成頁面“假死”箕戳,可通過重新加載的方式恢復(fù)
window.location.reload()
打印的時候?qū)⒁蛴〉牟糠衷O(shè)置為當(dāng)前頁面的全部內(nèi)容某残,打印完之后又將頁面恢復(fù)。
分別打印一個頁面上的多個區(qū)域:
//第一個打印區(qū)域的內(nèi)容
var printContents1 = document.getElementById('printArea1').innerHTML
//第二個打印區(qū)域的的內(nèi)容
var printContents2 = document.getElementById('printArea2').innerHTML
//頁面的所有內(nèi)容
var originalContents = document.body.innerHTML
//打印第一個區(qū)域
document.body.innerHTML = printContents1
window.print()
//打印第二個區(qū)域
document.body.innerHTML = printContents2
window.print()
//恢復(fù)頁面
document.body.innerHTML = originalContents
//直接恢復(fù)頁面可能會造成頁面“假死”陵吸,可通過重新加載的方式恢復(fù)
window.location.reload()
這種方法可以使得每次打印時要打印的內(nèi)容都在頁面開頭玻墅,并且對于超過一屏的打印也正確。
存在的問題:
打印完之后需手動將頁面恢復(fù)至原來的html結(jié)構(gòu)壮虫,恢復(fù)之后發(fā)現(xiàn)頁面“假死”澳厢,無法再進(jìn)行其他交互,因此我調(diào)用了window.location.reload()
將頁面刷新囚似。但是這樣做實際上是沒有保存頁面目前的一些數(shù)據(jù)和交互信息剩拢,因此用戶體驗也不好。
如果不希望犧牲用戶體驗谆构,可以將要打印的內(nèi)容寫入新的瀏覽器窗口并打開裸扶,打印完之后關(guān)閉該新窗口:
var printContents = document.getElementById('printArea').innerHTML
//打開打印窗口
var newWin = window.open()
newWin.document.write(printContents)
newWin.print()
//關(guān)閉打印窗口
newWin.close()
我們會發(fā)現(xiàn)框都,使用這種方法的話搬素,打印內(nèi)容的css樣式實際上是失效的呵晨,因為在打印窗口頁面并沒有引入相關(guān)的css,所以我們需要手動引入:
var printContents = document.getElementById('printArea').innerHTML
var newWin = window.open()
//引入css
var printCommonStyle=`
<style>
*{
box-sizing: border-box;
}
.text-center{
text-align: center;
}
a,a:link,a:visited,a:hover,a:active{
color: #000;
text-decoration: none;
}
/*設(shè)置打印時的table樣式*/
table{
border-spacing: 0px;
border-bottom: 1px solid;
}
th,td {
padding: 4px 4px;
word-break: break-all;
border-top: 1px solid;
border-left: 1px solid;
}
tr>th:last-child,
tr>td:last-child {
border-right: 1px solid;
}
</style>
`
newWin.document.write( printCommonStyle+printContents )
newWin.print()
newWin.close()
這樣也能實現(xiàn)一些場景下的打印要求(比如表格熬尺、文字等)摸屠。
2、js插件實現(xiàn)打印功能
下載為圖片:html2canvas + a標(biāo)簽download屬性
打印為PDF:html2canvas + jsPDF
首先我們看看這幾個js的使用方法:
1)html2canvas
步驟:引入html2canvas.js粱哼,在Promise.then中獲取轉(zhuǎn)換好的canvas:
//通過html2canvas把html渲染成canvas季二,然后獲取圖片數(shù)據(jù)
html2canvas(document.getElementById('showPart')).then(function(canvas) {
//將canvas轉(zhuǎn)成PDF或者下載圖片
//.........................................
});
2)下載圖片
其實要用到a標(biāo)簽的download特性:
//通過html2canvas把html渲染成canvas,然后獲取圖片數(shù)據(jù)
html2canvas(document.getElementById('showPart')).then(function(canvas) {
//下載圖片
var aElement=document.createElement('a');
aElement.setAttribute('href',imageData); //重點看這里
aElement.setAttribute('download','test.png'); //重點看這里
document.body.insertAdjacentElement('beforeend',aElement)
aElement.click();
});
3)jsPDF
(1)文字打印成PDF:
var doc=new jsPDF()
doc.text('hello world!',10,10)
doc.save('a4.pdf')
(2)圖片打印成PDF:
我們看看官網(wǎng)的例子:
注意:jsPDF需要的是data URL的圖片格式揭措。
借助于官網(wǎng)的例子胯舷,我們進(jìn)行一下模擬,代碼:
var imageData='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QA/wD/AP+gvaeTAAAAB3RJTUUH3gwKEAonDW4kCwAAAodJREFUaN7t2LtrFUEYxuFHTWGCBrzFS6WilcGgnSAoGLX2UgiChSGF2NtYiEII+C8E0oid0VqxUBDsFAUrRS0UUYkBlaNgvBQzMcclObvubLIp9q12l/lm3t/M7M73LY0aNWpUp5ZV2dnmC08LtXt3dffSA8iYX4F16I33nzGJn1VDJANkjPdgEMcxgLXx+Sc8wU3cRasqkCSAjPmtuIyTEWQutXADl/C6CoiuJPxZbcMYDuW068EZbMFwO0RZLS8b2Db7PcLM55lv1yCuxNjCL3+lABkzJ0rEnYixSUoF6NJ5z3dST4xN2sapAGuEr01ZDcQ+agNYm2hgjdlPbS0AVRyESX2kAkxiKiF+KvZRG8AUHifEP06cgGSAaSE9aJWIbcXY6ToBCLnNRIm4iRibpKpyoe0Yx4GCofdxFi9Jy4WqWAHRyBCu6bydWrHN0Iz5VC1UOn0Me82eEVN4hFuWUjo9DwSzBc3KeP9dpqCpwnxlADkw/6jKcrIygA3D90rFfRw7WA9AB8PLhG3TjdVYFZ9/xRd8E7bT76qA/gtgHuN92ClklruwAxuj+fZ34Cve4wWeCTXyc3xIASkEMIfxddiHo9gvlJS9/zEhv4U/Fa/wALfxUCYvKgKSO2DGfJ9QhJzGHmGrVKFvQl50XSj6/65KHkRHgIz5I7gozHhVB2BWv4QVGcGdIhDzArSZXy4c+yPCCiyGPsTJGo9Q80IUmcmjGF1E8+JYozic1zAPoBvnsH4Rzc9oPc7Lec/yADahvwbzM+qPHkoDdKnu710Z5Y6/UF+TRVMRgDohc8fO2x7TeBuvf9Vg/q2cmjkP4A1OFWi3UJqOHkoD/BDylUaNGjVqNKf+AN+rkUhAKMRGAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE3LTExLTEyVDExOjAyOjI0KzA4OjAwmpHX/gAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNC0xMi0xMFQxNjoxMDozOSswODowMOM3CTMAAABNdEVYdHNvZnR3YXJlAEltYWdlTWFnaWNrIDcuMC4xLTYgUTE2IHg4Nl82NCAyMDE2LTA5LTE3IGh0dHA6Ly93d3cuaW1hZ2VtYWdpY2sub3Jn3dmlTgAAABh0RVh0VGh1bWI6OkRvY3VtZW50OjpQYWdlcwAxp/+7LwAAABh0RVh0VGh1bWI6OkltYWdlOjpIZWlnaHQAMTI4Q3xBgAAAABd0RVh0VGh1bWI6OkltYWdlOjpXaWR0aAAxMjjQjRHdAAAAGXRFWHRUaHVtYjo6TWltZXR5cGUAaW1hZ2UvcG5nP7JWTgAAABd0RVh0VGh1bWI6Ok1UaW1lADE0MTgxOTkwMzk6CQwlAAAAEnRFWHRUaHVtYjo6U2l6ZQAxLjA3S0Lad01iAAAAX3RFWHRUaHVtYjo6VVJJAGZpbGU6Ly8vaG9tZS93d3dyb290L3NpdGUvd3d3LmVhc3lpY29uLm5ldC9jZG4taW1nLmVhc3lpY29uLmNuL3NyYy8xMTgyMS8xMTgyMTEyLnBuZ9ePzJoAAAAASUVORK5CYII='
var doc = new jsPDF()
doc.addImage(imageData,'png',0,0,100,100)
doc.save('resume.pdf')
4)得到data url
其實這個功能只是調(diào)用一個toDataURL的API而已绊含,所以不需要用什么插件桑嘶,直接調(diào)用就可以了:
//默認(rèn)的轉(zhuǎn)換類型:"image/png"
var imageData=canvas.toDataURL()
知道上述幾個API和插件的基本用法后,我們來將它們組合起來:先使用html2canvas把網(wǎng)頁轉(zhuǎn)成canvas躬充,再使用toDataURL()方法把canvas轉(zhuǎn)成data url逃顶,最后用jsPDF把data url轉(zhuǎn)成PDF,簡直完美充甚!
完整代碼如下:
html2canvas(document.getElementById('showPart')).then(function(canvas) {
//通過html2canvas把html渲染成canvas
document.body.appendChild(canvas);
//canvas轉(zhuǎn)成dataurl
var imageData=canvas.toDataURL()
//dataurl轉(zhuǎn)成PDF
var doc = new jsPDF('','pt','a4')
doc.addImage(imageData,'png', 0, 0, 595, 595/canvas.width * canvas.height) //使圖片占滿整張A4紙
doc.save('test.pdf')
});
------補(bǔ)充-------
測試發(fā)現(xiàn)以政,以上代碼得到的結(jié)果存在兩個嚴(yán)重問題:
- 當(dāng)圖片比較長時,超出A4紙長度的那部分圖片會被截掉
- 最終得到的PDF不清晰伴找,很模糊
我翻看了很多資料盈蛮,試了很多方法,分頁解決了技矮,但是得到的PDF還是很模糊眉反。目前還未解決,先在這里占個坑吧穆役,等到解決了再來整理寸五。
總之,目前還沒找到完美的方案來解決打印的問題耿币,如果您有什么解決方案梳杏,可以多多交流哦~~
參考:
1、Print <div id=“printarea”></div> only?
2淹接、Javascript 將html轉(zhuǎn)成pdf,下載,支持多頁哦
3十性、html導(dǎo)出pdf文件
4、問:html5 canvas繪制圖片模糊的問題