前端實現html轉pdf方法總結

最近要搞前端html轉pdf的功能。折騰了兩天,略有所收,踩了一些坑,因此作些記錄,爲後來的兄弟作些提示,也算是回饋社區。
通過一番調(sou)研(suo)發現html導出pdf通常有這幾種方式,各有各有優缺,下面簡單介紹。css

這篇文章說了啥

正文

經過打印預覽實現

介紹

經過打印預覽來實現導出pdf並非什麼稀奇事,通常瀏覽器(Chrome)在頁面手動Ctrl + P都能將當前頁進行打印預覽。在打印預覽的時候咱們更改打印方式,選擇將頁面保存爲PDF便可實現頁面保存爲PDF的功能。
好比此時我進行Ctrl + P就能夠看到這個功能。node

clipboard.png

程序中實現這個則要靠下面這個方法來實現:jquery

window.print(); // 在控制檯執行print()也能看到上面打印預覽的效果

固然能導出PDF只是主要需求,咱們還有一些其餘的需求git

  1. 只想將頁面的一部分導出爲PDF
  2. 咱們想導出的PDF是A4紙大小
  3. 咱們想導出的PDF是豎着的
  4. 咱們還想調整導出PDF的樣式
  5. ...

這些需求經過在對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來查看文檔,效果是同樣的。

clipboard.png

  • jsPDF-AutoTabledemo的表格作的很好看,可是他沒有提供代碼,那我怎麼看到他是怎麼實現的?

clipboard.png

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.jsjspdf.customfonts.debug.js這兩個文件致使的,只引用其中一個就行了。

  • jsPDF-AutoTablethead中的中文顯示亂碼

這個問題我找不到緣由,可是我找到了一個方法: 隱藏掉thead,經過在tbody中將第一排tr設置樣式來模擬thead。實現以下:

doc.autoTable(columns, data, {showHeader: 'never'}); // 不顯示thead

評價

html2canvas + jsPdf的方法直接圖轉pdf,簡單,可是質量差點。
jsPDF-CustomFonts-support的方法雖然質量上佔優點,但那個字體文件動輒好幾兆,甚至十幾兆,這對於前端來講是一個不小的開銷,對性能影響太。
此外,這兩種方式導出PDF都是點一下導出就會下載文件的,不須要用戶再次確認下載,這點用戶體驗仍是比較好的。

後端導出pdf

iTextwkhtmltopdfprince這三個都是後端生成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...

相關文章
相關標籤/搜索