博客 / 詳情

返回

前端 HTML 轉 PDF

🧑‍💻 寫在開頭

點贊 + 收藏 === 學會🤣🤣🤣

前端 HTML 轉 PDF 的工具函數,核心作用是:把網頁中指定 ID 的 DOM 元素(比如表格、報表、表單等),通過 html2canvas 和 jspdf 兩個庫轉換成 PDF 文件並下載到本地。

簡單説:它能讓用户 “一鍵下載” 網頁上的某個區域為 PDF(比如報表、數據統計頁、合同預覽頁等),還預留了 “水印功能” 的註釋代碼(可按需啓用)。

核心依賴説明

函數依賴兩個關鍵庫,必須先安裝才能使用:

ScreenShot_2026-01-16_173725_018

函數核心邏輯(分步拆解)

函數名 htmlToPdf,接收兩個參數:

  • title:下載的 PDF 文件名(比如 “2024 年報表”);
  • htmlId:需要轉換的 HTML 元素的 ID(比如 #report-container)。

整體流程:定位 HTML 元素 → 滾動置頂避免截圖不全 → (可選加水印)→ HTML 轉 Canvas → Canvas 轉 PDF → 下載 PDF

1. 準備工作:定位元素 + 滾動置頂

const element = document.querySelector(htmlId); // 找到要轉PDF的HTML元素
// 滾動置頂:避免元素被滾動條遮擋,導致截圖不全
window.pageYOffset = 0;
document.documentElement.scrollTop = 0;
document.body.scrollTop = 0;

2. 可選:添加水印(已註釋,需啓用可取消註釋)

註釋部分的邏輯是:創建一個帶文字水印(比如 “我是水印”)的 Canvas,作為背景圖添加到目標元素上,轉 PDF 時水印會一起被截取(適合需要版權保護的場景)。

3. HTML 轉 Canvas(核心步驟)

html2Canvas(element, {
  allowTaint: true, // 允許跨域圖片(如果元素內有跨域圖片需開啓)
  useCORS: true, // 啓用CORS跨域支持
  scale: 2, // 縮放2倍:提升PDF清晰度(代價是文件變大)
  height: element.scrollHeight, // 用元素實際滾動高度:避免只截取可視區域(關鍵!)
  windowHeight: element.scrollHeight
}).then(canvas => {
  // Canvas生成成功後,進入PDF生成步驟
});

4. Canvas 轉 PDF 並下載

const contentWidth = canvas.width; // Canvas寬度
const contentHeight = canvas.height; // Canvas高度
const pageHeight = (contentWidth * 841.89) / 592.28; // A4紙的高度(按比例計算)
let leftHeight = contentHeight; // 未生成PDF的剩餘高度
let position = 0; // PDF頁面偏移量

// 創建A4尺寸的PDF(縱向:"p" = portrait)
const pdf = new JsPDF("p", "pt", "a4");
// Canvas轉成圖片數據(jpeg格式,質量1.0)
const pageData = canvas.toDataURL("image/jpeg", 1.0);

// 處理分頁:如果內容高度超過1頁A4紙,自動分頁
if (leftHeight < pageHeight) {
  // 單頁:直接嵌入圖片(20是左右邊距,避免內容貼邊)
  pdf.addImage(pageData, "JPEG", 20, 20, imgWidth, imgHeight);
} else {
  // 多頁:循環截取內容,每滿1頁添加新頁面
  while (leftHeight > 0) {
    pdf.addImage(pageData, "JPEG", 20, position, imgWidth, imgHeight);
    leftHeight -= pageHeight;
    position -= 841.89; // 向下偏移A4紙高度
    if (leftHeight > 0) pdf.addPage(); // 剩餘內容不為空時,新增一頁
  }
}

// 觸發下載:文件名=title+".pdf"
pdf.save(title + ".pdf");

如何使用

1. 安裝依賴

# npm 安裝
npm install html2canvas jspdf --save

# pnpm 安裝
pnpm add html2canvas jspdf

2.創建一個htmlToPdf.js文件

import html2Canvas from "html2canvas";
import JsPDF from "jspdf";
// title:下載文件的名稱  htmlId:包裹的標籤的id
const htmlToPdf = (title, htmlId) => {
  const element = document.querySelector(htmlId);
  window.pageYOffset = 0;
  document.documentElement.scrollTop = 0;
  document.body.scrollTop = 0;
  setTimeout(() => {
    // // 以下注釋的是增加導出的pdf水印 !!!!!!!!!!!!!
    // const value = '我是水印'
    // //創建一個畫布
    // let can = document.createElement('canvas')
    // //設置畫布的長寬
    // can.width = 400
    // can.height = 500
    // let cans = can.getContext('2d') as any
    // //旋轉角度
    // cans.rotate((-15 * Math.PI) / 180)
    // cans.font = '18px Vedana'
    // //設置填充繪畫的顏色、漸變或者模式
    // cans.fillStyle = 'rgba(200, 200, 200, 0.40)'
    // //設置文本內容的當前對齊方式
    // cans.textAlign = 'left'
    // //設置在繪製文本時使用的當前文本基線
    // cans.textBaseline = 'Middle'
    // //在畫布上繪製填色的文本(輸出的文本,開始繪製文本的X座標位置,開始繪製文本的Y座標位置)
    // cans.fillText(value, can.width / 8, can.height / 2)
    // let div = document.createElement('div')
    // div.style.pointerEvents = 'none'
    // div.style.top = '20px'
    // div.style.left = '-20px'
    // div.style.position = 'fixed'
    // div.style.zIndex = '100000'
    // div.style.width = element.scrollHeight + 'px'
    // div.style.height = element.scrollHeight + 'px'
    // div.style.background =
    //   'url(' + can.toDataURL('image/png') + ') left top repeat'
    // element.appendChild(div) // 到頁面中
    html2Canvas(element, {
      allowTaint: true,
      useCORS: true,
      scale: 2, // 提升畫面質量,但是會增加文件大小
      height: element.scrollHeight, // 需要注意,element的 高度 寬度一定要在這裏定義一下,不然會存在只下載了當前你能看到的頁面   避雷避雷!!!
      windowHeight: element.scrollHeight
    }).then(function (canvas) {
      const contentWidth = canvas.width;
      const contentHeight = canvas.height;
      // 一頁pdf顯示html頁面生成的canvas高度;
      const pageHeight = (contentWidth * 841.89) / 592.28;
      // 未生成pdf的html頁面高度
      let leftHeight = contentHeight;
      // 頁面偏移
      let position = 0;
      // a4紙的尺寸[595.28,841.89],html頁面生成的canvas在pdf中圖片的寬高  //40是左右頁邊距
      const imgWidth = 595.28 - 40;
      const imgHeight = (592.28 / contentWidth) * contentHeight;
      const pageData = canvas.toDataURL("image/jpeg", 1.0);
      const pdf = new JsPDF("p", "pt", "a4");
      // 有兩個高度需要區分,一個是html頁面的實際高度,和生成pdf的頁面高度(841.89)
      // 當內容未超過pdf一頁顯示的範圍,無需分頁
      if (leftHeight < pageHeight) {
        pdf.addImage(pageData, "JPEG", 20, 20, imgWidth, imgHeight);
      } else {
        while (leftHeight > 0) {
          pdf.addImage(pageData, "JPEG", 20, position, imgWidth, imgHeight);
          leftHeight -= pageHeight;
          position -= 841.89;
          // 避免添加空白頁
          if (leftHeight > 0) {
            pdf.addPage();
          }
        }
      }
      pdf.save(title + ".pdf");
    });
  }, 1000);
};
export default htmlToPdf;

3. 在 Vue/React 中使用示例

<!-- Vue 示例:頁面中有一個要轉PDF的區域 -->
<template>
  <div>
    <!-- 要轉PDF的元素:必須有唯一ID -->
    <div id="report-container">
      <h1>2024年銷售報表</h1>
      <table>...</table> <!-- 報表內容 -->
    </div>
    <!-- 下載按鈕 -->
    <button @click="downloadPdf">下載PDF</button>
  </div>
</template>

<script>
import htmlToPdf from '@/utils/htmlToPdf'; // 導入函數

export default {
  methods: {
    downloadPdf() {
      // 調用函數:參數1=PDF文件名,參數2=目標元素ID(注意加#)
      htmlToPdf('2024年銷售報表', '#report-container');
    }
  }
}
</script>

常見問題與優化

1. 截圖不全 / 內容缺失?

  • 確保目標元素的 height/scrollHeight 正確(函數已處理,但如果元素是動態渲染的,可能需要調整 setTimeout 延遲時間,比如從 1000ms 改為 2000ms);
  • 避免元素內有 position: fixed 的內容(會被重複截取)。

2. 圖片跨域導致截圖空白?

  • 確保 html2Canvas 配置中 allowTaint: true 和 useCORS: true 已開啓;
  • 圖片服務器需配置 CORS 允許當前域名訪問。

3. PDF 清晰度太低?

  • 增大 scale 參數(比如改為 3),但會導致文件變大;
  • 把 toDataURL 的質量參數從 1.0 保留(已最優)。

4. 想要啓用水印?

  • 取消代碼中水印相關的註釋,修改 value 為你的水印文字(比如 “內部資料”);
  • 調整 rotate 旋轉角度、font 字體大小、fillStyle 透明度(0.4 為半透明)。

如果對您有所幫助,歡迎您點個關注,我會定時更新技術文檔,大家一起討論學習,一起進步。

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.