이 글에서는 HTML을 PDF로 변환하는 4가지 방법(코드 포함)을 소개합니다. 도움이 필요한 친구들이 참고할 수 있기를 바랍니다.
이 기사에서는 Node.js, Puppeteer, 헤드리스 Chrome 및 Docker를 사용하여 복잡한 스타일의 React 페이지에서 PDF 문서를 생성하는 방법을 보여 드리겠습니다.
배경: 몇 달 전 한 고객이 사용자가 React 페이지 콘텐츠를 PDF 형식으로 얻을 수 있는 기능을 개발해 달라고 요청했습니다. 이 페이지는 기본적으로 많은 SVG가 포함된 환자 사례에 대한 보고서 및 데이터 시각화입니다. 레이아웃을 조작하고 HTML 요소의 일부 재배열을 수행하기 위한 특별한 요청도 있습니다. 따라서 PDF에는 원본 React 페이지와 다른 스타일과 추가 콘텐츠가 있어야 합니다.
이 작업은 간단한 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') })
npm install html2canvas jspdf
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()
就这样!
请注意 html2canvas 的 onclone方法。当你在截图之前需要操纵 DOM(例如隐藏打印按钮)时,它是非常方便的。我看到过很多使用这个包的项目。但不幸的是,这不是我们想要的,因为我们需要在后端完成对 PDF 的创建工作。
方案2:只使用 PDF 库
NPM上有几个库,如 jsPDF(如上所述)或PDFKit。他们的问题是,如果我想使用这些库,我将不得不重新调整页面结构。这肯定会损害可维护性,因为我需要将所有后续更改应用到 PDF 模板和 React 页面中。
请看下面的代码。你需要亲自手动创建 PDF 文档。你需要遍历 DOM 并找出每个元素并将其转换为 PDF 格式,这是一项繁琐的工作。必须找到一个更简单的方法。
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 })
这段代码段来自 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,并实现我们的功能。
await page.type('#email', process.env.PDF_USER) await page.type('#password', process.env.PDF_PASSWORD) await page.click('#submit')
这是一个简单的功能,可导航到 URL 并生成站点的 PD F文件。
首先,我们启动浏览器(仅在 headless 模式下支持 PDF 生成),然后打开新页面,设置视口,并导航到提供的URL。
设置 waitUntil:'networkidle0'
选项意味着当至少500毫秒没有网络连接时,Puppeteer 会认为导航已完成。 (可以从 API docs 获取更多信息。)
之后,我们将 PDF 保存为变量,关闭浏览器并返回 PDF。
注意:page.pdf
方法接收 options
끝입니다!
html2canvas의 onclone 방식에 주목해주세요. 스크린샷을 찍기 전에 DOM을 조작해야 할 때(예: 인쇄 버튼 숨기기) 매우 편리합니다. 나는 이 패키지를 사용하는 많은 프로젝트를 보았습니다. 하지만 안타깝게도 백엔드에서 PDF 생성을 수행해야 하기 때문에 이는 우리가 원하는 것이 아닙니다.
옵션 2: PDF 라이브러리만 사용
#🎜🎜# NPM에는 jsPDF(위에서 언급한 대로) 또는 PDFKit과 같은 여러 라이브러리를 사용할 수 있습니다. 문제는 이러한 라이브러리를 사용하려면 페이지를 재구성해야 한다는 것입니다. PDF 템플릿과 React 페이지에 모든 후속 변경 사항을 적용해야 하므로 유지 관리성이 확실히 손상됩니다. #🎜🎜##🎜🎜#아래 코드를 참고해주세요. PDF 문서를 직접 수동으로 작성해야 합니다. DOM을 살펴보고 각 요소를 찾아 PDF 형식으로 변환해야 하는데 이는 지루한 작업입니다. 더 쉬운 방법을 찾아야 합니다. #🎜🎜#await page.addStyleTag({ content: '.nav { display: none} .navbar { border: 0px} #print-button {display: none}' })#🎜🎜#이 코드 조각은 PDFKit 문서에서 가져온 것입니다. 그러나 기존(계속 변경되는) HTML 페이지를 변환하는 대신 PDF 파일을 직접 생성하는 것이 목표라면 여전히 유용할 수 있습니다. #🎜🎜##🎜🎜#최종 솔루션 3: Node.js 기반 Puppeteer 및 헤드리스 Chrome#🎜🎜##🎜🎜#Puppeteer란 무엇인가요? 문서 내용은 다음과 같습니다. #🎜🎜##🎜🎜#
Puppeteer는 DevTools 프로토콜에서 Chrome 또는 Chromium을 제어하기 위한 고급 API를 제공하는 노드 라이브러리입니다. Puppeteer는 기본적으로 헤드리스 모드에서 Chrome 또는 Chromium을 실행하지만 전체(비헤드리스) 모드에서 실행되도록 구성할 수도 있습니다.#🎜🎜#기본적으로 Node.js에서 실행할 수 있는 브라우저입니다. 문서를 읽으면 가장 먼저 언급되는 것은 Puppeteer를 사용하여 #🎜🎜#스크린샷과 PDF#🎜🎜# 페이지를 생성할 수 있다는 것입니다. 훌륭한! 이것이 바로 우리가 원하는 것입니다. #🎜🎜##🎜🎜#먼저
npmi i puppeteer
를 사용하여 Puppeteer를 설치하고 기능을 구현하세요. #🎜🎜#printPDF.then(pdf => { res.set({ 'Content-Type': 'application/pdf', 'Content-Length': pdf.length }) res.send(pdf)#🎜🎜#이것은 URL로 이동하여 사이트의 PDF 파일을 생성하는 간단한 기능입니다. #🎜🎜##🎜🎜#먼저 브라우저를 시작한 다음(PDF 생성은 헤드리스 모드에서만 지원됨) 새 페이지를 열고 뷰포트를 설정한 후 제공된 URL로 이동합니다. #🎜🎜##🎜🎜#
waitUntil:'networkidle0'
옵션을 설정하면 Puppeteer는 최소 500밀리초 동안 네트워크 연결이 없으면 탐색이 완료된 것으로 간주합니다. (자세한 내용은 API 문서에서 확인할 수 있습니다.) #🎜🎜##🎜🎜##🎜🎜#이후 PDF를 변수로 저장하고 브라우저를 닫은 후 PDF로 돌아갑니다. #🎜🎜##🎜🎜##🎜🎜#참고: page.pdf
메서드는 options
개체를 수신하며 'path' 옵션을 사용하여 파일을 저장할 수 있습니다. 디스크에. 경로가 제공되지 않으면 PDF가 디스크에 저장되지 않고 대신 버퍼링됩니다. (나중에 어떻게 처리할지 논의하겠습니다.) #🎜🎜##🎜🎜# 보호된 페이지에서 PDF를 생성하기 전에 로그인해야 하는 경우 먼저 로그인 페이지로 이동하여 다음을 확인하세요. 양식 요소의 ID 또는 이름을 입력하고 양식을 제출합니다. #🎜🎜#function getPDF() { return axios.get(`${API_URL}/your-pdf-endpoint`, { responseType: 'arraybuffer', headers: { 'Accept': 'application/pdf' } })#🎜🎜#로그인 자격 증명을 항상 환경 변수에 저장하고 하드코딩하지 마세요! #🎜🎜#
样式控制
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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

부울 속성은 값없이 활성화되는 HTML의 특수 속성입니다. 1. 부울 속성은 입력 상자를 비활성화하는 등의 존재 여부에 따라 요소의 동작을 제어합니다. 2. 작업 원칙은 브라우저가 구문 분석 할 때 속성의 존재에 따라 요소 동작을 변경하는 것입니다. 3. 기본 사용법은 속성을 직접 추가하는 것이며, 고급 사용량은 JavaScript를 통해 동적으로 제어 될 수 있습니다. 4. 일반적인 실수는 값을 설정해야한다고 잘못 생각하고 올바른 글쓰기 방법은 간결해야합니다. 5. 모범 사례는 코드를 간결하게 유지하고 부울 속성을 합리적으로 사용하여 웹 페이지 성능 및 사용자 경험을 최적화하는 것입니다.

HTML 코드는 온라인 유효성 검사기, 통합 도구 및 자동화 된 프로세스를 통해 깨끗할 수 있습니다. 1) w3cmarkupvalidationservice를 사용하여 온라인으로 HTML 코드를 확인하십시오. 2) 실시간 확인을 위해 VisualStudioCode에 HTMLHINT 확장을 설치하고 구성하십시오. 3) htmltidy를 사용하여 시공 프로세스에서 HTML 파일을 자동으로 확인하고 청소하십시오.

HTML, CSS 및 JavaScript는 최신 웹 페이지를 구축하기위한 핵심 기술입니다. 1. HTML 웹 페이지 구조를 정의합니다. 2. CSS는 웹 페이지의 모양을 담당합니다.

HTML의 기능은 웹 페이지의 구조와 내용을 정의하는 것이며, 그 목적은 정보를 표시하는 표준화 된 방법을 제공하는 것입니다. 1) HTML은 타이틀 및 단락과 같은 태그 및 속성을 통해 웹 페이지의 다양한 부분을 구성합니다. 2) 콘텐츠 및 성능 분리를 지원하고 유지 보수 효율성을 향상시킵니다. 3) HTML은 확장 가능하므로 사용자 정의 태그가 SEO를 향상시킬 수 있습니다.

HTML의 미래 트렌드는 의미론 및 웹 구성 요소이며 CSS의 미래 트렌드는 CSS-In-JS 및 CSShoudini이며, JavaScript의 미래 트렌드는 WebAssembly 및 서버리스입니다. 1. HTML 시맨틱은 접근성과 SEO 효과를 향상시키고 웹 구성 요소는 개발 효율성을 향상 시키지만 브라우저 호환성에주의를 기울여야합니다. 2. CSS-in-JS는 스타일 관리 유연성을 향상 시키지만 파일 크기를 증가시킬 수 있습니다. CSShoudini는 CSS 렌더링의 직접 작동을 허용합니다. 3. Webosembly는 브라우저 애플리케이션 성능을 최적화하지만 가파른 학습 곡선을 가지고 있으며 서버리스는 개발을 단순화하지만 콜드 스타트 문제의 최적화가 필요합니다.

웹 개발에서 HTML, CSS 및 JavaScript의 역할은 다음과 같습니다. 1. HTML은 웹 페이지 구조를 정의하고, 2. CSS는 웹 페이지 스타일을 제어하고 3. JavaScript는 동적 동작을 추가합니다. 그들은 함께 현대 웹 사이트의 프레임 워크, 미학 및 상호 작용을 구축합니다.

HTML의 미래는 무한한 가능성으로 가득합니다. 1) 새로운 기능과 표준에는 더 많은 의미 론적 태그와 WebComponents의 인기가 포함됩니다. 2) 웹 디자인 트렌드는 반응적이고 접근 가능한 디자인을 향해 계속 발전 할 것입니다. 3) 성능 최적화는 반응 형 이미지 로딩 및 게으른로드 기술을 통해 사용자 경험을 향상시킬 것입니다.

웹 개발에서 HTML, CSS 및 JavaScript의 역할은 다음과 같습니다. HTML은 컨텐츠 구조를 담당하고 CSS는 스타일을 담당하며 JavaScript는 동적 동작을 담당합니다. 1. HTML은 태그를 통해 웹 페이지 구조와 컨텐츠를 정의하여 의미를 보장합니다. 2. CSS는 선택기와 속성을 통해 웹 페이지 스타일을 제어하여 아름답고 읽기 쉽게 만듭니다. 3. JavaScript는 스크립트를 통해 웹 페이지 동작을 제어하여 동적 및 대화식 기능을 달성합니다.


핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

Video Face Swap
완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

인기 기사

뜨거운 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

mPDF
mPDF는 UTF-8로 인코딩된 HTML에서 PDF 파일을 생성할 수 있는 PHP 라이브러리입니다. 원저자인 Ian Back은 자신의 웹 사이트에서 "즉시" PDF 파일을 출력하고 다양한 언어를 처리하기 위해 mPDF를 작성했습니다. HTML2FPDF와 같은 원본 스크립트보다 유니코드 글꼴을 사용할 때 속도가 느리고 더 큰 파일을 생성하지만 CSS 스타일 등을 지원하고 많은 개선 사항이 있습니다. RTL(아랍어, 히브리어), CJK(중국어, 일본어, 한국어)를 포함한 거의 모든 언어를 지원합니다. 중첩된 블록 수준 요소(예: P, DIV)를 지원합니다.

Eclipse용 SAP NetWeaver 서버 어댑터
Eclipse를 SAP NetWeaver 애플리케이션 서버와 통합합니다.

SublimeText3 Linux 새 버전
SublimeText3 Linux 최신 버전

에디트플러스 중국어 크랙 버전
작은 크기, 구문 강조, 코드 프롬프트 기능을 지원하지 않음
