搜尋
首頁web前端html教學HTML轉成PDF的4個方法介紹(附程式碼)

HTML轉成PDF的4個方法介紹(附程式碼)

Mar 30, 2019 am 10:57 AM
node.jspdf前端

這篇文章帶給大家的內容是關於把HTML轉成PDF的4個方法介紹(附程式碼),有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

在本文中,我將展示如何使用 Node.js、Puppeteer、headless Chrome 和 Docker 從樣式複雜的 React 頁面產生 PDF 文件。

背景:幾個月前,有個客戶要求我們開發一個功能,使用者可以得到 PDF 格式的 React 頁面內容。該頁面基本上是患者病例的報告和數據視覺化結果,其中包含許多 SVG。另外還有一些特殊的請求來操縱佈局,並對 HTML 元素進行一些重新排列。因此與原始的 React 頁面相比,PDF 中應該有不同的樣式和額外的內容。

由於這個任務比用簡單的 CSS 規則解決要複雜得多,所以我們先探討了可能的實作方法。我們找到了 3 個主要解決方案。這篇部落格文章將引導你了解它們的可能性並最終實施。

在客戶端還是伺服器端產生?

在客戶端和伺服器端都可以產生PDF檔案。但是讓後端處理它可能更有意義,因為你不想耗盡用戶瀏覽器可以提供的所有資源。

即便如此,我仍然會展示這兩種方法的解決方案。

方案1:從 DOM 製作螢幕截圖

乍一看,這個解決方案似乎是最簡單的,事實證明的確是這樣,但它有其自身的限制。如果你沒有特殊需求,例如在 PDF 中選擇文字或對文字進行搜索,那麼這就是一種簡單易用的方法。

此方法簡單明了:從頁面建立螢幕截圖,並把它放到 PDF 檔案中。非常直截了當。我們可以使用兩個套件來實作:

  • Html2canvas,根據DOM 產生截圖
  • jsPdf,一個產生PDF的函式庫
##開始編碼:

npm install html2canvas jspdf

import html2canvas from 'html2canvas'
import jsPdf from 'jspdf'
 
function printPDF () {
    const domElement = document.getElementById('your-id')
    html2canvas(domElement, { onclone: (document) => {
      document.getElementById('print-button').style.visibility = 'hidden'
}})
    .then((canvas) => {
        const img = canvas.toDataURL('image/png')
        const pdf = new jsPdf()
        pdf.addImage(imgData, 'JPEG', 0, 0, width, height)
        pdf.save('your-filename.pdf')
})
就這樣!

請注意 html2canvas 的 onclone方法。當你在截圖之前需要操縱 DOM(例如隱藏列印按鈕)時,它是非常方便的。我看到很多使用這個包的項目。但不幸的是,這不是我們想要的,因為我們需要在後端完成對 PDF 的建立工作。

方案2:只使用 PDF 函式庫

NPM上有幾個函式庫,如 jsPDF(如上所述)或PDFKit。他們的問題是,如果我想使用這些庫,我將不得不重新調整頁面結構。這肯定會損害可維護性,因為我需要將所有後續變更套用到 PDF 範本和 React 頁面中。

請看下面的程式碼。你需要親自手動建立 PDF 文件。你需要遍歷 DOM 並找出每個元素並將其轉換為 PDF 格式,這是一項繁瑣的工作。必須找到一個更簡單的方法。

doc = new PDFDocument
doc.pipe fs.createWriteStream('output.pdf')
doc.font('fonts/PalatinoBold.ttf')
   .fontSize(25)
   .text('Some text with an embedded font!', 100, 100)
 
doc.image('path/to/image.png', {
   fit: [250, 300],
   align: 'center',
   valign: 'center'
});
 
doc.addPage()
   .fontSize(25)
   .text('Here is some vector graphics...', 100, 100)
 
doc.end()
這段程式碼片段來自 PDFKit 文件。但是如果你的目標是直接產生一個 PDF 文件,而不是對一個已經存在的(並且不斷變化的)HTML 頁面進行轉換,它還是很有用的。

最終方案3:基於 Node.js 的 Puppeteer 和 Headless Chrome

什麼是 Puppeteer?其文件中寫道:


Puppeteer 是一個 Node 函式庫,它提供了一個進階 API 來控制 DevTools 協定上的 Chrome 或 Chromium。 Puppeteer 預設以 headless 模式執行 Chrome 或 Chromium,但其也可以被配置為完整的(non-headless)模式運作。
它本質上是一個可以從 Node.js 運行的瀏覽器。如果你有讀過它的文檔,其中首先提到的就是你可以用 Puppeteer 來

產生頁面的截圖和PDF。優秀!這正是我們想要的。

先用

npmi i puppeteer 安裝 Puppeteer,實現我們的功能。

const puppeteer = require('puppeteer')
 
async function printPDF() {
  const browser = await puppeteer.launch({ headless: true });
  const page = await browser.newPage();
  await page.goto('https://blog.risingstack.com', {waitUntil: 'networkidle0'});
  const pdf = await page.pdf({ format: 'A4' });
 
  await browser.close();
  return pdf
})
這是一個簡單的功能,可導航到 URL 並產生網站的 PD F檔案。

首先,我們啟動瀏覽器(僅在 headless 模式下支援 PDF 產生),然後開啟新頁面,設定視窗,並導航到提供的URL。

設定

waitUntil:'networkidle0' 選項表示當至少500毫秒沒有網路連線時,Puppeteer 會認為導覽已完成。 (可以從 API docs 取得更多資訊。)

之後,我們將 PDF 儲存為變量,關閉瀏覽器並返回 PDF。

注意:

page.pdf 方法接收 options 對象,你可以使用 'path' 選項將檔案儲存到磁碟。如果未提供路徑,則 PDF 將不會被儲存到磁碟,而是會得到緩衝區。 (稍後我將討論如何處理它。)

如果需要先登入才能從受保護的頁面產生PDF,首先你要導航到登入頁面,檢查表單元素的ID 或名稱,填寫它們,然後提交表單:

await page.type('#email', process.env.PDF_USER)
await page.type('#password', process.env.PDF_PASSWORD)
await page.click('#submit')
要始終將登入憑證保存在環境變數中,不要硬編碼!

样式控制

Puppeteer 也有这种样式操作的解决方案。你可以在生成 PDF 之前插入样式标记,Puppeteer 将生成具有已修改样式的文件。

await page.addStyleTag({ content: '.nav { display: none} .navbar { border: 0px} #print-button {display: none}' })

将文件发送到客户端并保存

好的,现在你已经在后端生成了一个 PDF 文件。接下来做什么?

如上所述,如果你不把文件保存到磁盘,将会得到一个缓冲区。你只需要把含有适当内容类型的缓冲区发送到前端即可。

printPDF.then(pdf => {
    res.set({ 'Content-Type': 'application/pdf', 'Content-Length': pdf.length })
    res.send(pdf)

现在,你只需在浏览器向服务器发送请求即可得到生成的 PDF。

function getPDF() {
 return axios.get(`${API_URL}/your-pdf-endpoint`, {
   responseType: 'arraybuffer',
   headers: {
     'Accept': 'application/pdf'
   }
 })

一旦发送了请求,缓冲区的内容就应该开始下载了。最后一步是将缓冲区数据转换为 PDF 文件。

savePDF = () => {
    this.openModal(‘Loading…’) // open modal
   return getPDF() // API call
     .then((response) => {
       const blob = new Blob([response.data], {type: 'application/pdf'})
       const link = document.createElement('a')
       link.href = window.URL.createObjectURL(blob)
       link.download = `your-file-name.pdf`
       link.click()
       this.closeModal() // close modal
     })
   .catch(err => /** error handling **/)
 }
<button>Save as PDF</button>

就这样!如果单击“保存”按钮,那么浏览器将会保存 PDF。

在 Docker 中使用 Puppeteer

我认为这是实施中最棘手的部分 —— 所以让我帮你节省几个小时的百度时间。

官方文档指出“在 Docker 中使用 headless Chrome 并使其运行起来可能会非常棘手”。官方文档有疑难解答部分,你可以找到有关用 Docker 安装 puppeteer 的所有必要信息。

如果你在 Alpine 镜像上安装 Puppeteer,请确保在看到页面的这一部分时再向下滚动一点。否则你可能会忽略一个事实:你无法运行最新的 Puppeteer 版本,并且你还需要用一个标记禁用 shm :

const browser = await puppeteer.launch({
  headless: true,
  args: ['--disable-dev-shm-usage']
});

否则,Puppeteer 子进程可能会在正常启动之前耗尽内存。

方案 3 + 1:CSS 打印规则

可能有人认为从开发人员的角度来看,简单地使用 CSS 打印规则很容易。没有 NPM 模块,只有纯 CSS。但是在跨浏览器兼容性方面,它的表现如何呢?

在选择 CSS 打印规则时,你必须在每个浏览器中测试结果,以确保它提供的布局是相同的,并且它不是100%能做到这一点。

例如,在给定元素后面插入一个 break-after 并不是一个多么高深的技术,但是你可能会惊讶的发现要在 Firefox 中使用它需要使用变通方法。

除非你是一位经验丰富的 CSS 大师,在创建可打印页面方面有很多的经验,否则这可能会非常耗时。

如果你可以使打印样式表保持简单,打印规则是很好用的。

让我们来看一个例子吧。

@media print {
    .print-button {
        display: none;
    }
    
    .content p {
        break-after: always;
    }
}

上面的 CSS 隐藏了打印按钮,并在每个 p 之后插入一个分页符,其中包含content 类。有一篇很棒的文章总结了你可以用打印规则做什么,以及它们有什么问题,包括浏览器兼容性。

考虑到所有因素,如果你想从不那么复杂的页面生成 PDF,CSS打印规则非常有效。

总结

让我们快速回顾前面介绍的方案,以便从 HTML 页面生成 PDF 文件:

从 DOM 产生截图:当你需要从页面创建快照时(例如创建缩略图)可能很有用,但是当你需要处理大量数据时就会有些捉襟见肘。

只用 PDF 库:如果你打算从头开始以编程方式创建 PDF 文件,这是一个完美的解决方案。否则,你需要同时维护 HTML 和 PDF 模板,这绝对是一个禁忌。

Puppeteer:尽管在 Docker 上工作相对困难,但它为我们的实现提供了最好的结果,而且编写代码也是最简单的。

CSS打印规则:如果你的用户受过足够的教育,知道如何把页面内容打印到文件,并且你的页面相对简单,那么它可能是最轻松的解决方案。正如你在我们的案例中所看到的,事实并非如此。

本篇文章到这里就已经全部结束了,更多其他精彩内容可以关注PHP中文网的HTML视频教程栏目!

以上是HTML轉成PDF的4個方法介紹(附程式碼)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:segmentfault。如有侵權,請聯絡admin@php.cn刪除
如何驗證您的HTML代碼?如何驗證您的HTML代碼?Apr 24, 2025 am 12:04 AM

HTML代碼可以通過在線驗證器、集成工具和自動化流程來確保其清潔度。 1)使用W3CMarkupValidationService在線驗證HTML代碼。 2)在VisualStudioCode中安裝並配置HTMLHint擴展進行實時驗證。 3)利用HTMLTidy在構建流程中自動驗證和清理HTML文件。

HTML與CSS和JavaScript:比較Web技術HTML與CSS和JavaScript:比較Web技術Apr 23, 2025 am 12:05 AM

HTML、CSS和JavaScript是構建現代網頁的核心技術:1.HTML定義網頁結構,2.CSS負責網頁外觀,3.JavaScript提供網頁動態和交互性,它們共同作用,打造出用戶體驗良好的網站。

HTML作為標記語言:其功能和目的HTML作為標記語言:其功能和目的Apr 22, 2025 am 12:02 AM

HTML的功能是定義網頁的結構和內容,其目的在於提供一種標準化的方式來展示信息。 1)HTML通過標籤和屬性組織網頁的各個部分,如標題和段落。 2)它支持內容與表現分離,提升維護效率。 3)HTML具有可擴展性,允許自定義標籤增強SEO。

HTML,CSS和JavaScript的未來:網絡開發趨勢HTML,CSS和JavaScript的未來:網絡開發趨勢Apr 19, 2025 am 12:02 AM

HTML的未來趨勢是語義化和Web組件,CSS的未來趨勢是CSS-in-JS和CSSHoudini,JavaScript的未來趨勢是WebAssembly和Serverless。 1.HTML的語義化提高可訪問性和SEO效果,Web組件提升開發效率但需注意瀏覽器兼容性。 2.CSS-in-JS增強樣式管理靈活性但可能增大文件體積,CSSHoudini允許直接操作CSS渲染。 3.WebAssembly優化瀏覽器應用性能但學習曲線陡,Serverless簡化開發但需優化冷啟動問題。

HTML:結構,CSS:樣式,JavaScript:行為HTML:結構,CSS:樣式,JavaScript:行為Apr 18, 2025 am 12:09 AM

HTML、CSS和JavaScript在Web開發中的作用分別是:1.HTML定義網頁結構,2.CSS控製網頁樣式,3.JavaScript添加動態行為。它們共同構建了現代網站的框架、美觀和交互性。

HTML的未來:網絡設計的發展和趨勢HTML的未來:網絡設計的發展和趨勢Apr 17, 2025 am 12:12 AM

HTML的未來充滿了無限可能。 1)新功能和標準將包括更多的語義化標籤和WebComponents的普及。 2)網頁設計趨勢將繼續向響應式和無障礙設計發展。 3)性能優化將通過響應式圖片加載和延遲加載技術提升用戶體驗。

HTML與CSS vs. JavaScript:比較概述HTML與CSS vs. JavaScript:比較概述Apr 16, 2025 am 12:04 AM

HTML、CSS和JavaScript在網頁開發中的角色分別是:HTML負責內容結構,CSS負責樣式,JavaScript負責動態行為。 1.HTML通過標籤定義網頁結構和內容,確保語義化。 2.CSS通過選擇器和屬性控製網頁樣式,使其美觀易讀。 3.JavaScript通過腳本控製網頁行為,實現動態和交互功能。

HTML:是編程語言還是其他?HTML:是編程語言還是其他?Apr 15, 2025 am 12:13 AM

HTMLISNOTAPROGRAMMENGUAGE; ITISAMARKUMARKUPLAGUAGE.1)htmlStructures andFormatSwebContentusingtags.2)itworkswithcsssforstylingandjavascript for Interactivity,增強WebevebDevelopment。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

SublimeText3 英文版

SublimeText3 英文版

推薦:為Win版本,支援程式碼提示!

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

WebStorm Mac版

WebStorm Mac版

好用的JavaScript開發工具

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),