最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

前端實(shí)現(xiàn)HTML轉(zhuǎn)PDF的兩種主流方案詳解

 更新時(shí)間:2026年03月01日 15:50:10   作者:likuolei  
本文詳細(xì)對(duì)比了前端生成PDF的兩種主流方案:客戶(hù)端(html2canvas+jsPDF)和服務(wù)端(Puppeteer/Playwright),從原理、優(yōu)缺點(diǎn)、適用場(chǎng)景、核心代碼、坑點(diǎn)與優(yōu)化等方面進(jìn)行分析,推薦了適合不同場(chǎng)景的方案,需要的朋友可以參考下

目前前端生成 PDF 最主流的兩種方案是:

  1. 客戶(hù)端方案:html2canvas + jsPDF(或其封裝庫(kù) html2pdf.js)
  2. 服務(wù)端方案Puppeteer / Playwright(Node.js 無(wú)頭瀏覽器)

這兩種方案幾乎占據(jù)了 90% 以上的實(shí)際項(xiàng)目。下面從原理、優(yōu)缺點(diǎn)、適用場(chǎng)景、核心代碼、坑點(diǎn)與優(yōu)化等維度進(jìn)行深度對(duì)比。

一、核心對(duì)比表(快速?zèng)Q策)

維度客戶(hù)端方案(html2canvas + jsPDF)服務(wù)端方案(Puppeteer / Playwright)勝出方
實(shí)現(xiàn)難度★☆☆☆☆(最簡(jiǎn)單)★★★☆☆(需后端)客戶(hù)端
生成質(zhì)量中等(樣式丟失常見(jiàn))極高(接近瀏覽器打印效果)服務(wù)端
中文/字體支持較差(需特殊處理)優(yōu)秀(可加載本地字體)服務(wù)端
大文件 / 長(zhǎng)頁(yè)面容易卡頓、崩潰穩(wěn)定服務(wù)端
分頁(yè)控制弱(需 hack)強(qiáng)(支持 @page、頁(yè)眉頁(yè)腳)服務(wù)端
部署復(fù)雜度零(純前端)中等(需 Node 服務(wù))客戶(hù)端
性能壓力前端瀏覽器承擔(dān)后端服務(wù)器承擔(dān)看場(chǎng)景
安全性高(客戶(hù)端)中(后端需注意 HTML 注入)客戶(hù)端
2026 年推薦場(chǎng)景簡(jiǎn)單報(bào)表、導(dǎo)出預(yù)覽、H5 小程序正式合同、發(fā)票、復(fù)雜報(bào)告、打印級(jí) PDF

二、方案一:客戶(hù)端 —— html2canvas + jsPDF(最常用)

原理

  1. html2canvas 把 DOM 元素渲染成 Canvas(像素級(jí)截圖)
  2. jsPDF 把 Canvas 轉(zhuǎn)為 PDF 文件并下載

推薦庫(kù)

  • 直接用 html2pdf.js(封裝版,最推薦)
  • 或手動(dòng)組合 html2canvas + jsPDF

核心代碼(Vue 3 + html2pdf.js)

<template>
  <div ref="content">
    <!-- 你的 HTML 內(nèi)容 -->
    <h1>發(fā)票標(biāo)題</h1>
    <table>...</table>
  </div>
  <button @click="exportPDF">導(dǎo)出 PDF</button>
</template>

<script setup>
import html2pdf from 'html2pdf.js'

const content = ref(null)

const exportPDF = () => {
  const opt = {
    margin: [10, 10, 10, 10],
    filename: 'report.pdf',
    image: { type: 'jpeg', quality: 0.98 },
    html2canvas: {
      scale: 2,                    // 清晰度(2倍最合適)
      useCORS: true,               // 跨域圖片
      letterRendering: true
    },
    jsPDF: {
      unit: 'mm',
      format: 'a4',
      orientation: 'portrait'
    }
  }

  html2pdf().set(opt).from(content.value).save()
}
</script>

優(yōu)點(diǎn)

  • 零后端,部署最簡(jiǎn)單
  • 適合 H5、小程序、內(nèi)部工具

致命缺點(diǎn)(2026 年仍未徹底解決)

  • 復(fù)雜 CSS3(flex、grid、陰影、漸變)容易變形
  • 中文字體模糊或缺失
  • 超長(zhǎng)頁(yè)面容易內(nèi)存溢出
  • 分頁(yè)控制極差(經(jīng)常出現(xiàn)表格斷行、頁(yè)眉頁(yè)腳難處理)

優(yōu)化技巧

  • 使用 scale: 2 提升清晰度
  • 提前把需要導(dǎo)出的內(nèi)容克隆到一個(gè)隱藏的 div 中,專(zhuān)門(mén)優(yōu)化樣式
  • 對(duì)于表格推薦使用 jspdf-autotable 插件單獨(dú)處理

三、方案二:服務(wù)端 —— Puppeteer / Playwright(質(zhì)量之王)

原理

啟動(dòng)無(wú)頭瀏覽器(Headless Chrome / Firefox / WebKit),加載完整 HTML 頁(yè)面后,直接調(diào)用 page.pdf() 生成 PDF。

2026 年推薦:Playwright(已全面超越 Puppeteer)

Playwright 優(yōu)勢(shì):多瀏覽器支持、自動(dòng)等待、API 更現(xiàn)代、穩(wěn)定性更高。

核心代碼(Node.js + Express)

// pdfService.js
const { chromium } = require('playwright')

async function htmlToPdf(htmlContent) {
  const browser = await chromium.launch({ headless: true })
  const page = await browser.newPage()

  // 關(guān)鍵:設(shè)置視口和打印樣式
  await page.setContent(htmlContent, { waitUntil: 'networkidle' })

  const pdfBuffer = await page.pdf({
    format: 'A4',
    printBackground: true,
    margin: { top: '15mm', bottom: '15mm', left: '10mm', right: '10mm' },
    displayHeaderFooter: true,
    headerTemplate: '<div style="font-size:10px;width:100%;text-align:center;">頁(yè)眉</div>',
    footerTemplate: '<div style="font-size:10px;width:100%;text-align:center;">第 <span class="pageNumber"></span> 頁(yè)</div>'
  })

  await browser.close()
  return pdfBuffer
}

前端調(diào)用示例

const res = await fetch('/api/export-pdf', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ html: document.getElementById('content').outerHTML })
})

const blob = await res.blob()
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = 'report.pdf'
a.click()

優(yōu)點(diǎn)

  • 生成效果幾乎和瀏覽器打印一致
  • 原生支持 @page、page-break-before/after 分頁(yè)控制
  • 中文字體完美(可加載本地字體或系統(tǒng)字體)
  • 支持頁(yè)眉頁(yè)腳、加密、水印、目錄等高級(jí)功能

缺點(diǎn)

  • 需要部署 Node 服務(wù)
  • 并發(fā)高時(shí)消耗服務(wù)器資源(可使用 puppeteer-cluster / playwright-cluster 做池化)

四、最終推薦(2026 年真實(shí)選擇)

  • 推薦客戶(hù)端方案:內(nèi)部工具、簡(jiǎn)單報(bào)表、H5 活動(dòng)頁(yè)、快速 MVP
  • 強(qiáng)烈推薦服務(wù)端方案:合同、發(fā)票、正式報(bào)告、需要精確分頁(yè)和美觀樣式的場(chǎng)景
  • 混合方案(最優(yōu)解):前端負(fù)責(zé)編輯預(yù)覽 + 服務(wù)端負(fù)責(zé)最終生成 PDF(目前大廠(chǎng)主流做法)

你現(xiàn)在要做的是哪類(lèi) PDF?

  • 簡(jiǎn)單數(shù)據(jù)報(bào)表?
  • 合同/發(fā)票類(lèi)正式文件?
  • 還是需要頁(yè)眉頁(yè)腳 + 精確分頁(yè)的復(fù)雜報(bào)告?

告訴我具體需求,我可以給你對(duì)應(yīng)方案的最優(yōu)完整代碼模板。

以上就是前端實(shí)現(xiàn)HTML轉(zhuǎn)PDF的兩種主流方案詳解的詳細(xì)內(nèi)容,更多關(guān)于前端HTML轉(zhuǎn)PDF方案的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • checkbox全選所涉及到的知識(shí)點(diǎn)介紹

    checkbox全選所涉及到的知識(shí)點(diǎn)介紹

    checkbox全選涉及到的知識(shí)點(diǎn)比如IE里起作用,火狐不起作用,getElementById()與getElementsByName()的區(qū)別等等
    2013-12-12
  • 編寫(xiě)更好的JavaScript條件式和匹配條件的技巧(小結(jié))

    編寫(xiě)更好的JavaScript條件式和匹配條件的技巧(小結(jié))

    這篇文章主要介紹了編寫(xiě)更好的JavaScript條件式和匹配條件的技巧(小結(jié)),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • electron-builder打包配置詳解

    electron-builder打包配置詳解

    本文主要介紹了electron-builder打包配置詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • 詳解javaScript中Number數(shù)字類(lèi)型的使用

    詳解javaScript中Number數(shù)字類(lèi)型的使用

    Number和Math都屬于JavaScript中的內(nèi)置對(duì)象,Number數(shù)字類(lèi)型作為基礎(chǔ)數(shù)據(jù)類(lèi)型,我們?cè)陂_(kāi)發(fā)過(guò)程中會(huì)經(jīng)常用到,包括數(shù)字精度的格式化,還有字符串轉(zhuǎn)換成數(shù)字等操作。本文將詳細(xì)講解其用法,感興趣的可以了解一下
    2022-04-04
  • JavaScript實(shí)現(xiàn)滑塊補(bǔ)圖驗(yàn)證碼效果

    JavaScript實(shí)現(xiàn)滑塊補(bǔ)圖驗(yàn)證碼效果

    這篇文章主要給大家介紹了JavaScript如何實(shí)現(xiàn)滑塊補(bǔ)圖驗(yàn)證碼效果,文章通過(guò)代碼示例介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴可以參考閱讀下
    2023-07-07
  • 使用JavaScript實(shí)現(xiàn)ajax的實(shí)例代碼

    使用JavaScript實(shí)現(xiàn)ajax的實(shí)例代碼

    實(shí)現(xiàn)ajax之前必須要?jiǎng)?chuàng)建一個(gè) XMLHttpRequest 對(duì)象。這是必須的。那么對(duì)使用js實(shí)現(xiàn)ajax的代碼感興趣的朋友可以參考下本文
    2016-05-05
  • element?table?點(diǎn)擊某一行中按鈕加載功能實(shí)現(xiàn)

    element?table?點(diǎn)擊某一行中按鈕加載功能實(shí)現(xiàn)

    在Element UI中,實(shí)現(xiàn)表格(element-table)中的這種功能通常涉及到數(shù)據(jù)處理和狀態(tài)管理,這篇文章主要介紹了element?table?點(diǎn)擊某一行中按鈕加載功能,需要的朋友可以參考下
    2024-06-06
  • javascript實(shí)現(xiàn)原生ajax的幾種方法介紹

    javascript實(shí)現(xiàn)原生ajax的幾種方法介紹

    項(xiàng)目中不需要加載jquery這種龐大的js插件要使用到ajax這種功能該如何辦呢?下面和大家分享幾種利用javascript實(shí)現(xiàn)原生ajax的方法
    2013-09-09
  • Three?cannon-es?基礎(chǔ)使用示例詳解

    Three?cannon-es?基礎(chǔ)使用示例詳解

    Cannon.js可以在多種瀏覽器上運(yùn)行,并且支持移動(dòng)設(shè)備和桌面設(shè)備,這使得開(kāi)發(fā)者可以輕松地在各種平臺(tái)上開(kāi)發(fā)和運(yùn)行物理模擬應(yīng)用程序,這篇文章主要介紹了Three?cannon-es?基礎(chǔ)使用,需要的朋友可以參考下
    2024-05-05
  • JS動(dòng)態(tài)給對(duì)象添加屬性和值的實(shí)現(xiàn)方法

    JS動(dòng)態(tài)給對(duì)象添加屬性和值的實(shí)現(xiàn)方法

    下面小編就為大家?guī)?lái)一篇JS動(dòng)態(tài)給對(duì)象添加屬性和值的實(shí)現(xiàn)方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-10-10

最新評(píng)論

金乡县| 阳信县| 临颍县| 沙河市| 新丰县| 宝丰县| 新源县| 凉城县| 高雄市| 汉源县| 茂名市| 双牌县| 澄城县| 东莞市| 南川市| 林口县| 仁布县| 柘城县| 富源县| 琼中| 图片| 七台河市| 青海省| 鄂托克旗| 巫山县| 保靖县| 开江县| 云梦县| 六安市| 奈曼旗| 堆龙德庆县| 靖宇县| 黔西县| 翼城县| 从化市| 陈巴尔虎旗| 图木舒克市| 绵竹市| 瑞安市| 长顺县| 北宁市|