這也許就是AI無法代替人的原因,只需一行代碼就可以實現純前端 html 轉矢量 pdf 的功能
// 引入 dompdf.js庫
import dompdf from "dompdf.js";
dompdf(document.querySelector("#capture")).then(function (blob) {
//文件操作
});
實現效果(複雜表格)
在前端生態裡,把網頁內容生成 PDF 一直是一個常見但不簡單的需求。從報表導出、小票生成、合同下載到打印排版,很多專案或多或少都有會遇到。市面上常見的方案大致有以下幾類:
但是這些方案都有各自的局限性,
使用 jspdf 生成如圖簡單的 pdf
就需要如此複雜的代碼,如果要生成複雜的 pdf, 比如包含表格、圖片、圖表等內容,那使用成本就更高了。
function generateChinesePDF() {
// Check if jsPDF is loaded
if (typeof window.jspdf === "undefined") {
alert("jsPDF library has not finished loading, please try again later");
return;
}
const { jsPDF } = window.jspdf;
const doc = new jsPDF();
// Note: Default jsPDF does not support Chinese, this is just a demo
// In real projects you need to add Chinese font support
doc.setFontSize(16);
doc.text("Chinese Text Support Demo", 20, 30);
doc.setFontSize(12);
doc.text("Note: Default jsPDF does not support Chinese characters.", 20, 50);
doc.text("You need to add Chinese font support for proper display.", 20, 70);
// Draw some graphics for demonstration
doc.setFillColor(255, 182, 193);
doc.rect(20, 90, 60, 30, "F");
doc.setTextColor(0, 0, 0);
doc.text("粉紅色矩形", 25, 108);
doc.setFillColor(173, 216, 230);
doc.rect(100, 90, 60, 30, "F");
doc.text("淺藍色矩形", 105, 108);
doc.save("chinese-example.pdf");
}
但是現在,有了 dompdf.js,你只需要一行代碼,就可以完成比這個複雜 10 倍的 PDF 生成任務,html頁面所見即所得,可以將複雜的css樣式轉化成pdf
dompdf(document.querySelector("#capture")).then(function (blob) {
//文件操作
});
而且,dompdf.js 生成的 PDF 是矢量的,非圖片式的,高清晰度的,文字可以選中、複製、搜索等操作(在支持的 PDF 閱讀器環境下),區別於客戶端將 HTML 渲染為圖片(如 html2canvas + jsPDF)然後再封裝為 PDF。
其實 dompdf.js 也是基於 html2canvas+jspdf 實現的,但是為什麼 dompdf.js 生成的 pdf 文件可以二次編輯,更清晰,體積小呢?
不同於普通的 html2canvas + jsPDF 方案,將 dom 內容生成功能圖片,再將圖片內容用 jspdf 繪製到 pdf 上,這就導致了生成的 pdf 文件體積大,無法編輯,放大後會模糊。
html2canvas 原理簡介
1. DOM 樹遍歷
html2canvas 從指定的 DOM 節點開始,遞歸遍歷所有子節點,構建一個描述頁面結構的內部渲染隊列。
2. 樣式計算
對每個節點調用 window.getComputedStyle()
獲取最終的 CSS 屬性值。這一步至關重要,因為它包含了所有 CSS 規則(內聯、內部、外部樣式表)層疊計算後的最終結果。
3. 渲染模型構建
將每個 DOM 節點和其計算樣式封裝成渲染對象,包含繪製所需的完整資訊:位置(top, left)、尺寸(width, height)、背景、邊框、文本內容、字體屬性、層級關係(z-index)等。
4. Canvas 上下文創建
在內存中創建 canvas 元素,獲取其 2D 渲染上下文(CanvasRenderingContext2D)。
5. 瀏覽器繪製模擬
按照 DOM 的堆疊順序和佈局規則,遍歷渲染隊列,將每個元素繪製到 Canvas 上。這個過程實質上是將 CSS 屬性"翻譯"成對應的繪製 API 調用:
CSS 屬性 | 傳統 Canvas API | dompdf.js 中的 jsPDF API |
---|---|---|
background-color |
ctx.fillStyle + ctx.fillRect() |
doc.setFillColor() + doc.rect(x, y, w, h, 'F') |
border |
ctx.strokeStyle + ctx.strokeRect() |
doc.setDrawColor() + doc.rect(x, y, w, h, 'S') |
color , font-family , font-size |
ctx.fillStyle , ctx.font + ctx.fillText() |
doc.setTextColor() + doc.setFont() + doc.text() |
border-radius |
arcTo() 或 bezierCurveTo() 創建剪切路徑 |
doc.roundedRect() 或 doc.lines() 繪製圓角 |
image |
ctx.drawImage() |
doc.addImage() |
核心創新:API 替換,底層是封裝了 jsPDF 的 API
dompdf.js 的關鍵突破在於改造了 html2canvas 的 canvas-renderer.ts
文件,將原本輸出到 Canvas 的繪製 API 替換為 jsPDF 的 API 調用。這樣就實現了從 DOM 直接到 PDF 的轉換,生成真正可編輯、可搜索的 PDF 文件,而不是傳統的圖片格式。
目前實現的功能
npm install dompdf.js --save
<script src="https://cdn.jsdelivr.net/npm/dompdf.js@latest/dist/dompdf.js"></script>
import dompdf from "dompdf.js";
dompdf(document.querySelector("#capture"), {
useCORS: true, //是否允許跨域
})
.then(function (blob) {
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "example.pdf";
document.body.appendChild(a);
a.click();
})
.catch(function (err) {
console.log(err, "err");
});
dompdf.js 讓前端 PDF 生成變得前所未有的簡單:無需後端、無需繁瑣配置、一行代碼即可輸出矢量、可檢索、可複製的專業文檔。無論是簡歷、報告還是發票,它都能輕鬆勝任。 歡迎在你的專案中使用它 。
如果它幫到了你,歡迎去 github.com/lmn1919/dom… 點個 Star,提優化,共建專案。