国产精品一区二区久久久-99久久久精品免费看国产-久久九九99热这里只有精品-漂亮人妻被中出中文字幕久久-五月情综合网站久久-福利姬3d全彩办公室色欲-av网站在线播放网站-亚洲日本岛国动作片在线观看-男人的天堂啊啊啊啊

日志樣式

將HTML表格轉(zhuǎn)換成精美的PDF,幾種生成PDF的解決方案.

  • 標(biāo)簽 :

包含表格、圖表和圖形的Web應(yīng)用程序通常包含將數(shù)據(jù)導(dǎo)出為PDF的選項(xiàng)。你有沒有想過,作為一個(gè)用戶,當(dāng)你點(diǎn)擊那個(gè)按鈕時(shí),幕后發(fā)生了什么?

作為開發(fā)人員,如何讓PDF輸出看起來更專業(yè)?大多數(shù)免費(fèi)的在線PDF導(dǎo)出器實(shí)際上只是將HTML內(nèi)容轉(zhuǎn)換為PDF,而不進(jìn)行任何額外的格式化,這會(huì)使數(shù)據(jù)難以閱讀。如果你也能添加諸如頁眉和頁腳、頁碼或重復(fù)的表列標(biāo)題等內(nèi)容呢?像這樣的小點(diǎn)綴,對(duì)把一份看起來很業(yè)余的文件變成一份優(yōu)雅的文件有很大的幫助。

最近,我探索了幾種生成PDF的解決方案,并建立了這個(gè)Demo程序來展示結(jié)果。所有的代碼也可以在Github上找到。讓我們開始吧!

Demo程序概述

將HTML表格轉(zhuǎn)換成精美的PDF,幾種生成PDF的解決方案

 

我們的Demo程序包含一個(gè)冗長(zhǎng)的樣式表和四個(gè)將表導(dǎo)出為PDF的按鈕。該應(yīng)用是用基本的HTML、CSS和JavaScript構(gòu)建的,但你可以使用你的UI框架或選擇的庫輕松創(chuàng)建相同的輸出。

每個(gè)導(dǎo)出按鈕都使用不同的方法生成PDF。從右到左查看,第一個(gè)使用原生瀏覽器打印功能,第二個(gè)使用名為jsPDF的開源庫,第三個(gè)使用另一個(gè)名為pdfmake的開源庫,最后,第四個(gè)使用名為DocRaptor的付費(fèi)服務(wù)。

讓我們一一探討每個(gè)解決方案。

原生瀏覽器打印功能

首先,我們考慮使用瀏覽器的內(nèi)置工具導(dǎo)出PDF。在查看任何網(wǎng)頁時(shí),你可以通過右鍵單擊任意位置,然后從菜單中選擇“打印”選項(xiàng)來輕松地打印頁面。這將打開一個(gè)對(duì)話框,供你選擇打印設(shè)置。但是,你實(shí)際上不必打印文檔。對(duì)話框還提供了將文檔保存為PDF的選項(xiàng),這就是我們要做的。在JavaScript中 window 對(duì)象公開了一個(gè) print 方法,所以我們可以寫一個(gè)簡(jiǎn)單的JavaScript函數(shù),并將其附加到我們的一個(gè)按鈕上,就像這樣:

function downloadPDFWithBrowserPrint() {
  window.print();
}
document.querySelector('#browserPrint').addEventListener('click', downloadPDFWithBrowserPrint);

以下是Google Chrome瀏覽器的輸出:

將HTML表格轉(zhuǎn)換成精美的PDF,幾種生成PDF的解決方案

 

我對(duì)這里的輸出感到驚喜,雖然它并不華麗——內(nèi)容只是黑白色的,但主要的表格樣式卻被完整地保留了下來。此外,這七個(gè)頁面中的每一個(gè)都包含表列標(biāo)題和頁腳,我認(rèn)為瀏覽器可以智能地獲取這些信息,這是由于我在構(gòu)建結(jié)構(gòu)合理的表時(shí)選擇了語義HTML。

然而,我不喜歡瀏覽器在PDF中包含的額外頁面元數(shù)據(jù)??拷敳?,我們看到日期和HTML頁面標(biāo)題。在頁面的底部,我們看到了打印這篇文章的網(wǎng)站以及頁碼。

如果我保存這個(gè)文檔的唯一目的是為了看數(shù)據(jù),那么Chrome瀏覽器做得很好。不過,文檔頂部和底部多出的幾行文字雖然有用,但并沒有讓它看起來很專業(yè)。

另外需要注意的是,不同瀏覽器的原生打印功能是不一樣的。如果我們用Safari瀏覽器打印同樣的文檔呢?輸出如下:

將HTML表格轉(zhuǎn)換成精美的PDF,幾種生成PDF的解決方案

 

你會(huì)注意到表格看起來大致相同,頁面頁眉和頁腳內(nèi)容也是如此。但是,表列標(biāo)題和表腳不重復(fù)!這是沒有幫助的,因?yàn)楫?dāng)你忘記任何給定列包含什么數(shù)據(jù)時(shí),你需要返回到第一頁。第一頁的表格底部也有點(diǎn)被切斷,因?yàn)闉g覽器試圖在創(chuàng)建下一頁之前盡可能多地?cái)D進(jìn)內(nèi)容。

如此看來,瀏覽器的輸出并不理想,會(huì)因用戶選擇的瀏覽器不同而不同。

jsPDF

接下來讓我們考慮一個(gè)名為jsPDF的開源庫。這個(gè)庫已經(jīng)存在了至少5年,每周從NPM的下載量持續(xù)超過20萬次??梢哉f這是一個(gè)很受歡迎的、經(jīng)過實(shí)戰(zhàn)檢驗(yàn)的庫。

將HTML表格轉(zhuǎn)換成精美的PDF,幾種生成PDF的解決方案

 

jsPDF的使用也相當(dāng)簡(jiǎn)單。你可以創(chuàng)建一個(gè)新的jsPDF類的實(shí)例,給它一個(gè)你想導(dǎo)出的HTML內(nèi)容的引用,然后提供任何其他附加的設(shè)置,如頁邊距大小或文檔標(biāo)題。

function downloadPDFWithjsPDF() {
  var doc = new jspdf.jsPDF('p', 'pt', 'a4');

  doc.html(document.querySelector('#styledTable'), {
    callback: function (doc) {
      doc.save('MLB World Series Winners.pdf');
    },
    margin: [60, 60, 60, 60],
    x: 32,
    y: 32,
  });
}

document.querySelector('#jsPDF').addEventListener('click', downloadPDFWithjsPDF);

在內(nèi)部,jsPDF使用了一個(gè)名為html2canvas.的庫。顧名思義,html2canvas 接收 HTML 內(nèi)容,并將其轉(zhuǎn)化為存儲(chǔ)在 HTML <canvas> 元素上的圖像,然后 jsPDF 接收該畫布內(nèi)容并將其保存。

讓我們看一下使用jsPDF的輸出:

將HTML表格轉(zhuǎn)換成精美的PDF,幾種生成PDF的解決方案

 

乍一看,這看起來還不錯(cuò)! PDF包含我們漂亮的藍(lán)色標(biāo)題和條紋表行背景。它不包含瀏覽器打印方法所包含的任何多余頁面元數(shù)據(jù)。

但是,請(qǐng)注意在第一頁和第二頁之間發(fā)生了什么。表格一直延伸到第一頁的底部,然后在第二頁的頂部直接接上。沒有應(yīng)用額外的邊距,而且表文本內(nèi)容有可能被切成兩半。

該P(yáng)DF也不包括重復(fù)的表列標(biāo)題或表腳,這與我們?cè)赟afari的打印功能中看到的問題相同。

雖然jsPDF是一個(gè)強(qiáng)大的庫,但當(dāng)導(dǎo)出的內(nèi)容只能容納在一個(gè)頁面上時(shí),這個(gè)工具似乎效果最好。

pdfmake

讓我們看一下我們的第二個(gè)開源庫pdfmake。NPM每周下載量超過30萬次,壽命長(zhǎng)達(dá)7年,這個(gè)庫甚至比jsPDF更受歡迎,更資深。

將HTML表格轉(zhuǎn)換成精美的PDF,幾種生成PDF的解決方案

 

在為我的demo程序構(gòu)建導(dǎo)出功能時(shí),pdfmake的配置要比jsPDF難得多。原因是pdfmake使用你提供的數(shù)據(jù)從頭開始構(gòu)建PDF文檔,而不是將頁面上現(xiàn)有的HTML內(nèi)容轉(zhuǎn)換為PDF。這意味著,我必須為它提供PDF表格的頁眉、頁腳、內(nèi)容和布局的數(shù)據(jù),而不是為pdfmake提供一個(gè)對(duì)我的HTML表格的引用。這導(dǎo)致我的代碼有很多重復(fù),我先在HTML中寫了表格,然后用pdfmake為PDF導(dǎo)出重新建表。

代碼如下:

function downloadPDFWithPDFMake() {
  var tableHeaderText = [...document.querySelectorAll('#styledTable thead tr th')].map(thElement => ({ text: thElement.textContent, style: 'tableHeader' }));

  var tableRowCells = [...document.querySelectorAll('#styledTable tbody tr td')].map(tdElement => ({ text: tdElement.textContent, style: 'tableData' }));
  var tableDataAsRows = tableRowCells.reduce((rows, cellData, index) => {
    if (index % 4 === 0) {
      rows.push([]);
    }

    rows[rows.length - 1].push(cellData);
    return rows;
  }, []);

  var docDefinition = {
    header: { text: 'MLB World Series Winners', alignment: 'center' },
    footer: function(currentPage, pageCount) { return ({ text: `Page ${currentPage} of ${pageCount}`, alignment: 'center' }); },
    content: [
      {
        style: 'tableExample',
        table: {
          headerRows: 1,
          body: [
            tableHeaderText,
            ...tableDataAsRows,
          ]
        },
        layout: {
          fillColor: function(rowIndex) {
            if (rowIndex === 0) {
              return '#0f4871';
            }
            return (rowIndex % 2 === 0) ? '#f2f2f2' : null;
          }
        },
      },
    ],
    styles: {
      tableExample: {
        margin: [0, 20, 0, 80],
      },
      tableHeader: {
        margin: 12,
        color: 'white',
      },
      tableData: {
        margin: 12,
      },
    },
  };
  pdfMake.createPdf(docDefinition).download('MLB World Series Winners');
}

document.querySelector('#pdfmake').addEventListener('click', downloadPDFWithPDFMake);

在我們完全否定pdfmake之前,我們先來看看輸出。

將HTML表格轉(zhuǎn)換成精美的PDF,幾種生成PDF的解決方案

 

不是太寒酸!我們可以為表包含樣式,這樣我們?nèi)匀豢梢詮?fù)制藍(lán)色列標(biāo)題和條紋表行背景。我們還得到了重復(fù)的表列標(biāo)題,以便于跟蹤我們?cè)诿總€(gè)頁面的每個(gè)列中看到的數(shù)據(jù)。

pdfmake還允許我加入頁眉和頁腳,所以很容易添加頁碼。但你會(huì)注意到,第一頁和第二頁之間的表格內(nèi)容仍然沒有完全分開。分頁符將2002年的一行部分地分割在兩頁之間。

總體看來,pdfmake最大的優(yōu)勢(shì)在于從頭開始構(gòu)建PDF。例如,如果你想根據(jù)某些訂單數(shù)據(jù)生成發(fā)票,而你實(shí)際上并沒有在web應(yīng)用程序的頁面上顯示發(fā)票,那么pdfmake將是一個(gè)很好的選擇。

DocRaptor

最后一個(gè)我們要考慮的選項(xiàng)是DocRaptor。DocRaptor與我們探討的前三個(gè)選項(xiàng)不同的是,它是一種付費(fèi)服務(wù)。它使用Prince HTML-to-PDF引擎來生成其PDF輸出。該服務(wù)也通過API使用,因此你的代碼會(huì)碰到一個(gè)外部API端點(diǎn),然后該端點(diǎn)會(huì)返回PDF文檔。

將HTML表格轉(zhuǎn)換成精美的PDF,幾種生成PDF的解決方案

 

DocRaptor的基本配置相當(dāng)簡(jiǎn)單,你向它提供你的文檔名稱,你要?jiǎng)?chuàng)建的文檔類型(在我們的例子中是 'pdf'),以及要使用的HTML內(nèi)容。根據(jù)你的需要,還有數(shù)百種不同配置的選擇,但基本配置是一個(gè)很好的起點(diǎn)。

這是我使用的:

function downloadPDFWithDocRaptor() {
  DocRaptor.createAndDownloadDoc('YOUR_API_KEY_HERE', {
    test: true, // test documents are free, but watermarked
    type: 'pdf',
    name: 'MLB World Series Winners',
    document_content: document.querySelector('html').innerHTML,
  })
}

document.querySelector('#docRaptor').addEventListener('click', downloadPDFWithDocRaptor);

讓我們看一下DocRaptor生成的PDF導(dǎo)出:

將HTML表格轉(zhuǎn)換成精美的PDF,幾種生成PDF的解決方案

 

現(xiàn)在有一個(gè)好看的文檔了! 我們可以保留我們漂亮的表格樣式。表格的列頭和表腳在每一頁上都是重復(fù)的,表格的行數(shù)不會(huì)被切掉,而且頁面四面都有適當(dāng)大小的邊距,每個(gè)頁面的頁眉也是重復(fù)的,每個(gè)頁面底部的頁碼也是重復(fù)的。

要?jiǎng)?chuàng)建頁眉和頁腳文本,DocRaptor建議你使用一些CSS與 @page 選擇器,就像這樣。

@page {
  margin-top: 80px;
  margin-bottom: 80px;
  @top {
    content: "MLB World Series Winners"
  }
  @bottom {
    /* 具有計(jì)數(shù)器功能的頁腳可插入頁面計(jì)數(shù)器 */
    content: "Page " counter(page) " of " counter(pages)
  }
}

在PDF輸出方面,DocRaptor無疑是贏家。

總結(jié)

那么,你的應(yīng)用要選擇哪種方案呢?如果你想要最簡(jiǎn)單的解決方案,而且不需要專業(yè)的文檔,那么原生瀏覽器的打印功能應(yīng)該就可以了。如果你需要對(duì)PDF輸出進(jìn)行更多的控制,那么你就需要使用一個(gè)庫。

當(dāng)涉及到基于UI中顯示的HTML生成的單頁內(nèi)容時(shí),jsPDF就會(huì)大放異彩。pdfmake在從數(shù)據(jù)而不是HTML中生成PDF內(nèi)容時(shí)效果最好。DocRaptor是其中功能最強(qiáng)大的一款,它擁有簡(jiǎn)單的API和漂亮的PDF輸出。但同樣,與其他不同的是,它是一項(xiàng)付費(fèi)服務(wù)。然而,如果你的業(yè)務(wù)依賴于優(yōu)雅、專業(yè)的文檔生成,DocRaptor是非常值得的。

天津市犀思科技有限公司是專業(yè)從事web應(yīng)用定制開發(fā)的一家公司,主營(yíng)業(yè)務(wù)包括定制營(yíng)銷型網(wǎng)站建設(shè)微信小程序開發(fā)、微信公眾號(hào)開發(fā)APP定制開發(fā)、天津企業(yè)微信開發(fā)、ERP、CRM、OA等企業(yè)應(yīng)用場(chǎng)景信息化解決方案等服務(wù),致力于成為中國領(lǐng)先的IT服務(wù)及行業(yè)解決方案的提供商。


發(fā)表評(píng)論

電子郵件地址不會(huì)被公開。 必填項(xiàng)已用*標(biāo)注

看不清?點(diǎn)擊更換