最近要搞前端html轉pdf的功能。折騰了兩天,略有所收,踩了一些坑,因此作些記錄,爲後來的兄弟作些提示,也算是回饋社區。
通過一番調(sou)研(suo)發現html導出pdf通常有這幾種方式,各有各有優缺,下面簡單介紹。css
這篇文章說了啥
-
前端實現(着重)html
-
後端實現(湊數)前端
正文
經過打印預覽實現
介紹
經過打印預覽來實現導出pdf並非什麼稀奇事,通常瀏覽器(Chrome)在頁面手動Ctrl + P
都能將當前頁進行打印預覽。在打印預覽的時候咱們更改打印方式,選擇將頁面保存爲PDF
便可實現頁面保存爲PDF的功能。
好比此時我進行Ctrl + P
就能夠看到這個功能。node
程序中實現這個則要靠下面這個方法來實現:jquery
window.print(); // 在控制檯執行print()也能看到上面打印預覽的效果
固然能導出PDF只是主要需求,咱們還有一些其餘的需求git
- 只想將頁面的一
部分導出爲PDF
- 咱們想導出的PDF是
A4紙大小
- 咱們想導出的PDF是
豎着的
- 咱們還想調整導出PDF的
樣式
- ...
這些需求經過在對css中媒體查詢
的定義就能夠實現github
@media print { @page { size: A4 portrait; // A4大小 縱向 } .other-ele { // 打印時將不須要的元素隱藏 display: none; } .pdf-title { // 只在打印時候顯示的元素 display: block; } .panel-sm { // 打印時候改變某些元素的樣式 margin: 0; border: 1px solid #bce8f1; } }
更多的設置能夠參考:CSS 打印npm
最佳實踐
須要提醒的是:若是要改變原有樣式,最好是在元素上新加一個
class或者id來寫,而不是在原有class上寫。好比有這樣一個元素canvas
<h1 class="title">我是PDF標題</h1>
打印時候要把這個字體大小設置成18px的話,咱們不能這麼寫segmentfault
@media print{ .title { // not work font-size: 18px; } }
這樣寫試不起做用的。想要生效得在元素上新加一個class類寫
<h1 class="title title-print">我是PDF標題</h1>
@media print{ .title-print { font-size: 18px; } }
通過實踐,這樣寫才能夠生效。
庫或者插件
有人可能以爲這樣寫略有麻煩,別擔憂,總有人會讓麻煩的事情變得簡單,這我的若是不是你,那就必定是他。
基於window.print()
有人封裝了一些插件:
- PrintArea能夠簡單的實現部分區域打印,他的原理是經過把要打印的部分放入一個新的iframe而後觸發這個iframe的print。這個插件不太穩定,會出現空白,請酌情使用。
- jQuery.print比上面的稍微好點,支持了一些css方面的東西,具體看這個jQuery.print中文配置參數
評價
這種方法前端實現,靈活簡單,並且在頁面還原上是很好
的,生成pdf的過程不須要本身操心
,頁面樣式還可控
,能夠說是很是不錯的。可是由於瀏覽器對print
方法的支持不一
(具體支持狀況戳這裏),因此目前也就只能在Chrome上用用。另外,這個方法還須要用戶點一下保存按鈕,用戶體驗上也不太好
。
經過jsPdf實現
介紹
jsPdf是一個能夠把html轉成pdf的插件,有人多人在用。可是吧,老外作的不少東西沒考慮過英文以外的語言(這個能夠理解,我要作個啥確定也是作成中文的,我纔不考慮啥日語英語阿拉伯語呢),這個東西也不例外的不支持中文,那咋辦呢,不少兄弟想了辦法:
曲線救國 | html2canvas + jsPdf
既然你不支持中文,勞資也懶得跟你廢話,勞資我把頁面轉成圖片,怕不怕,圖片再導出PDF照樣中!這種方式很常見、很省事,問題也不少圖片拉伸、模糊,最重要這樣導出的PDF是沒有靈魂的,由於他裏面的內容都是圖片,不能複製。由於沒有靈魂,因此我沒有采用這種方法,若是你喜歡這種能夠參照這篇文章Javascript 將html轉成pdf,下載,支持多頁哦(html2canvas 和 jsPDF),寫的很詳細。
硬生生支持 | jsPDF-CustomFonts-support
既然你不支持其餘語言是吧,那我寫個插件出來搞到你支持爲止。幹這活兒的是一個來自韓國的哥們兒,他寫一個能夠支持其餘語言的插件jsPDF-CustomFonts-support。原理大概就是利用把你提供的字體文件轉成base64格式,而後作成一個js文件,拿這個js文件當作字庫。恩,我喜歡這種強上的作法。並且這樣導出的pdf內容是能夠複製的,簡直驚喜。因而,我採用了這樣的方式。
我當時是順着這哥們兒的道往前走的jsPDF生成pdf文件和中文編碼,這個過程是很是曲折與動人的,具體不表,只講裏面遇到的問題。
最佳實踐
掛幾個裏面遇到的比較坑的錯誤
-
jsPdf
官網的api文檔打不開
雖然文檔頁面打不開,可是在他的github倉庫裏是有docs
這個目錄的,並且目錄下也有文檔,那咱們就把這個倉庫下載來,在本地打開docs/index.html
來查看文檔,效果是同樣的。
-
jsPDF-AutoTable
demo的表格作的很好看,可是他沒有提供代碼,那我怎麼看到他是怎麼實現的?
demo的實現都在這個examples.js
中,沒有混淆,沒有壓縮,能夠依葫蘆畫瓢仿一個demo的表格。
- 如何生成本身的字體文件
jsPDF-CustomFonts-support
默認提供了一個字體文件,可是裏面有不少漢字不能正常顯示,因此你須要本身生成一個字體文件。怎麼生生成呢?你須要這樣:
git clone https://github.com/sphilee/jsPDF-CustomFonts-support cd jsPDF-CustomFonts-support npm install mv fontFilePath/fontName.ttf ./jsPDF-CustomFonts-support/fonts/ # 把你準備的`.ttf`格式字體,放入`jsPDF-CustomFonts-support/fonts/`目錄下 node makeFonts.js
而後jsPDF-CustomFonts-support/dist/default_vfs.js
就是你要的字體文件。
- Uncaught TypeError: jsPDFAPI.addFileToVFS is not a function
這個錯誤是jsPDF-CustomFonts-support
中報出的,是由於在1.4.0
如下版本的時候jsPDF
還不支持addFileToVFS
這個方法,因此最好的方法是使用最新的jspdf版本
用下面這個版本的jspdf替換掉報錯的。
<script src="https://unpkg.com/jspdf@latest/dist/jspdf.min.js"></script>
- Cannot read property 'widths' of undefined
這個錯誤是在jsPDF-AutoTable
中報出的,是由於同時引入jspdf.customfonts.min.js
和jspdf.customfonts.debug.js
這兩個文件致使的,只引用其中一個就行了。
-
jsPDF-AutoTable
thead中的中文顯示亂碼
這個問題我找不到緣由,可是我找到了一個方法: 隱藏掉thead,經過在tbody中將第一排tr設置樣式來模擬thead。實現以下:
doc.autoTable(columns, data, {showHeader: 'never'}); // 不顯示thead
評價
html2canvas + jsPdf
的方法直接圖轉pdf,簡單,可是質量差點。jsPDF-CustomFonts-support
的方法雖然質量上佔優點,但那個字體文件動輒好幾兆,甚至十幾兆,這對於前端來講是一個不小的開銷,對性能影響太。
此外,這兩種方式導出PDF都是點一下導出就會下載文件的,不須要用戶再次確認下載,這點用戶體驗仍是比較好的。
後端導出pdf
iText
、wkhtmltopdf
、prince
這三個都是後端生成pdf的工具。這三個都沒有node api。故很少說。想看具體的比較能夠參考這篇文章html頁面導出爲pdf(jsPDF、iText、wkhtmltopdf)。
參考
https://segmentfault.com/a/11...
https://segmentfault.com/a/11...
https://segmentfault.com/a/11...
https://blog.csdn.net/JodenHe...
https://blog.csdn.net/huyuyan...