欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JavaScript實(shí)現(xiàn)html轉(zhuǎn)pdf的三種方法詳解

 更新時(shí)間:2024年02月23日 10:47:52   作者:cooljser  
近期項(xiàng)目需要實(shí)現(xiàn)將?html?頁面轉(zhuǎn)換成?pdf?報(bào)告的需求,經(jīng)過一番調(diào)研以及結(jié)合過往經(jīng)驗(yàn),發(fā)現(xiàn)了三種技術(shù)方案,下面我們就來看看它們的具體實(shí)現(xiàn)步驟吧

近期項(xiàng)目需要實(shí)現(xiàn)將 html 頁面轉(zhuǎn)換成 pdf 報(bào)告的需求,經(jīng)過一番調(diào)研以及結(jié)合過往經(jīng)驗(yàn),發(fā)現(xiàn)了有如下三種技術(shù)方案,本篇文章主要內(nèi)容是基于這三種不同方案的 demo 實(shí)現(xiàn)及對比。

方案選型

  • html2canvas + jspdf
  • wkhtmltopdf
  • node + puppeteer

準(zhǔn)備工作

利用 chatgpt 生成一個(gè)報(bào)告的 html 模板,每頁包含了一個(gè)表格和一個(gè)由 echarts 生成的柱狀圖。實(shí)際項(xiàng)目中基本也是這樣的內(nèi)容,文字 + charts,所以用這個(gè)來測試具有一定的參考意義,生成的 html 模板如下:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Report Page</title>
    <!-- ECharts庫 -->
    <script src="https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js"></script>
    <style>
      body {
        font-family: Arial, sans-serif;
        margin: 20px;
      }
      .page {
        margin-bottom: 40px;
      }
      .chart {
        width: 600px;
        height: 400px;
        margin-top: 20px;
      }
      table {
        width: 100%;
        border-collapse: collapse;
      }
      th,
      td {
        text-align: left;
        padding: 8px;
        border-bottom: 1px solid #ddd;
      }
    </style>
  </head>
  <body>
    <div class="page" id="page1">
      <h2>Page 1 - Data and Chart</h2>
      <table>
        <tr>
          <th>Item</th>
          <th>Value</th>
        </tr>
        <tr>
          <td>Item 1</td>
          <td>100</td>
        </tr>
        <tr>
          <td>Item 2</td>
          <td>200</td>
        </tr>
        <!-- 更多列表數(shù)據(jù) -->
      </table>
      <div id="chart1" class="chart"></div>
    </div>    

    <div class="page" id="page2">
      <table>
        <tr>
          <th>Item</th>
          <th>Value</th>
        </tr>
        <tr>
          <td>Item 1</td>
          <td>100</td>
        </tr>
        <tr>
          <td>Item 2</td>
          <td>200</td>
        </tr>
        <!-- 更多列表數(shù)據(jù) -->
      </table>
      <h2>Page 2 - Data and Chart</h2>
      <!-- 類似的列表和圖表占位符 -->
      <div id="chart2" class="chart"></div>
    </div>    

    <div class="page" id="page3">
      <table>
        <tr>
          <th>Item</th>
          <th>Value</th>
        </tr>
        <tr>
          <td>Item 1</td>
          <td>100</td>
        </tr>
        <tr>
          <td>Item 2</td>
          <td>200</td>
        </tr>
        <!-- 更多列表數(shù)據(jù) -->
      </table>
      <h2>Page 3 - Data and Chart</h2>
      <!-- 類似的列表和圖表占位符 -->
      <div id="chart3" class="chart"></div>
    </div>

    <script>
      // ECharts 圖表示例
      var chart1 = echarts.init(document.getElementById('chart1'));
      var option1 = {
        title: {text: 'ECharts 示例 1'},
        tooltip: {},
        xAxis: {data: ['類別1', '類別2', '類別3', '類別4']},
        yAxis: {},
        series: [{type: 'bar', data: [5, 20, 36, 10]}]
      };
      chart1.setOption(option1);

      // 為page2和page3重復(fù)上面的過程,設(shè)置不同的option配置
      var chart2 = echarts.init(document.getElementById('chart2'));
      chart2.setOption(option1);
      var chart3 = echarts.init(document.getElementById('chart3'));
      chart3.setOption(option1);
    </script>
  </body>
</html>

使用 http-server 在 html 頁面目錄下啟動(dòng)一個(gè) web 服務(wù)器(沒有 http-server, 參考這里安裝 www.npmjs.com/package/http-server)

http-server . -p 9090

訪問 http://127.0.0.1:9090/report.html,即可看到對應(yīng)的報(bào)告模板頁面,如下:

wkhtmltopdf

到這里 wkhtmltopdf.org/downloads.html 下載系統(tǒng)對應(yīng)版本的安裝包,然后安裝好

執(zhí)行如下命令,即可生成 pdf

wkhtmltopdf http://127.0.0.1:9090/report.html report.pdf

查看生成的 pdf 內(nèi)容,能正常顯示,看起來也沒啥問題

實(shí)際報(bào)告肯定是有多頁的,接下來我們嘗試一下看看如何分頁。在 page1 和 page2 元素后分別加入一個(gè)

元素,對應(yīng)的 class 如下:

.page-break-after {
	page-break-after: always;
}

然后再次執(zhí)行轉(zhuǎn)換命令,得到的 pdf 如下:

問題

偶爾會(huì)卡在某個(gè)進(jìn)度不動(dòng),不知道為啥

執(zhí)行時(shí)間不穩(wěn)定,時(shí)快時(shí)慢

putteteer

安裝就不多說明了,自行 google。安裝好后,同樣讓 chatgpt 生成一段測試的代碼,如下:

const puppeteer = require('puppeteer');

async function savePageAsPDF(url, outputPath) {
  // 啟動(dòng)瀏覽器
  const browser = await puppeteer.launch();
  // 打開新頁面
  const page = await browser.newPage();
  // 導(dǎo)航到指定URL
  await page.goto(url, { waitUntil: 'networkidle2' });
  // 保存頁面為PDF
  await page.pdf({ path: outputPath, format: 'A4' });
  // 關(guān)閉瀏覽器
  await browser.close();
  console.log(`PDF已保存到:${outputPath}`);
}

// 調(diào)用函數(shù)保存網(wǎng)頁為PDF
savePageAsPDF('http://127.0.0.1:9090/report.html', 'report1.pdf').catch(console.error);

執(zhí)行轉(zhuǎn)換腳本

node index.js

得到的 pdf 內(nèi)容如下,看起來也沒啥問題

html2canvas + jspdf

引入 html2canvas 和 jspdf 相關(guān)腳本

<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.3.2/html2canvas.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.3.1/jspdf.umd.min.js"></script>

添加下載按鈕及轉(zhuǎn)換函數(shù)

<button onclick="convertToPDF()">Convert to PDF</button>

<script>
		async function addPage(id, pdf) {
			const element = document.getElementById(id);

			// 使用 html2canvas 渲染指定元素
			const canvas = await html2canvas(element, {scale: 2});
			const imgData = canvas.toDataURL('image/png');

			// 使用 jsPDF 創(chuàng)建PDF文檔
			const imgProps = pdf.getImageProperties(imgData);
			const pdfWidth = pdf.internal.pageSize.getWidth();
			// const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width;
			const pdfHeight = (imgProps.height / imgProps.width) * pdfWidth;
			// const pdfHeight = pdf.internal.pageSize.getHeight();
			console.log(imgProps.width, pdfWidth, pdfHeight, pdf.internal.pageSize.getHeight());
			pdf.addImage(imgData, 'JPEG', 0, 0, pdfWidth, pdfHeight, 'NONE', 'FAST');
		}

		async function convertToPDF() {
			const pdf = new window.jspdf.jsPDF();

			await addPage('page1', pdf);
			pdf.addPage();
			await addPage('page2', pdf);
			pdf.addPage();
			await addPage('page3', pdf);

			pdf.save('converted.pdf');
		}
</script>

訪問頁面,點(diǎn)擊按鈕即可下載 pdf 了,內(nèi)容如下:

方案對比

wkhtmltopdf,依賴后端,配置比較靈活,但是速度好像不穩(wěn)定

pupeteer,依賴后端,生成的 pdf 比較準(zhǔn)確,質(zhì)量也還可以

html2canvas + jspdf,純前端實(shí)現(xiàn),依賴少

以上就是JavaScript實(shí)現(xiàn)html轉(zhuǎn)pdf的三種方法詳解的詳細(xì)內(nèi)容,更多關(guān)于JavaScript html轉(zhuǎn)pdf的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 對于JavaScript繼承你到底了解多少

    對于JavaScript繼承你到底了解多少

    js的繼承機(jī)制不同于傳統(tǒng)的面向?qū)ο笳Z言,采用原型鏈實(shí)現(xiàn)繼承,基本思想是利用原型讓一個(gè)引用類型繼承另一個(gè)引用類型的屬性和方法,下面這篇文章主要給大家介紹了關(guān)于JS繼承的相關(guān)資料,需要的朋友可以參考下
    2021-09-09
  • JS開發(fā)自己的類庫實(shí)例分析

    JS開發(fā)自己的類庫實(shí)例分析

    這篇文章主要介紹了JS開發(fā)自己的類庫,結(jié)合實(shí)例形式分析了javascript開發(fā)類庫的原理、組成及實(shí)現(xiàn)方法,需要的朋友可以參考下
    2019-08-08
  • JavaScript 和 C++實(shí)現(xiàn)雙向交互

    JavaScript 和 C++實(shí)現(xiàn)雙向交互

    本文主要介紹了在CEF中實(shí)現(xiàn)JavaScript和C++的雙向交互,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-02-02
  • ECMAScript 6即將帶給我們新的數(shù)組操作方法前瞻

    ECMAScript 6即將帶給我們新的數(shù)組操作方法前瞻

    這篇文章主要介紹了ECMAScript 6即將帶給我們新的數(shù)組操作方法前瞻,需要的朋友可以參考下
    2015-01-01
  • javascript 尋找錯(cuò)誤方法整理

    javascript 尋找錯(cuò)誤方法整理

    為了以后能快速尋找到這方面的錯(cuò)誤,節(jié)約更多的時(shí)間,下面將問題的解決方法整理了一下
    2014-06-06
  • js實(shí)現(xiàn)京東秒殺倒計(jì)時(shí)功能

    js實(shí)現(xiàn)京東秒殺倒計(jì)時(shí)功能

    這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)京東秒殺倒計(jì)時(shí)功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • Firefox/Chrome/Safari的中可直接使用$/$$函數(shù)進(jìn)行調(diào)試

    Firefox/Chrome/Safari的中可直接使用$/$$函數(shù)進(jìn)行調(diào)試

    偶然發(fā)現(xiàn)的,頁面中沒有引入Prototype和jQuery??刂婆_(tái)中敲$卻發(fā)現(xiàn)是一個(gè)函數(shù)。又試著敲$$,也是個(gè)function
    2012-02-02
  • HTML中事件觸發(fā)列表與解說

    HTML中事件觸發(fā)列表與解說

    HTML中事件觸發(fā)列表與解說...
    2007-07-07
  • JS實(shí)現(xiàn)倒序輸出的幾種常用方法示例

    JS實(shí)現(xiàn)倒序輸出的幾種常用方法示例

    這篇文章主要介紹了JS實(shí)現(xiàn)倒序輸出的幾種常用方法,結(jié)合實(shí)例形式分析了JavaScript字符串與數(shù)組的轉(zhuǎn)換、變量、分割、反轉(zhuǎn)等相關(guān)操作技巧,需要的朋友可以參考下
    2019-04-04
  • JavaScript中setInterval()和setTimeout()的用法及區(qū)別

    JavaScript中setInterval()和setTimeout()的用法及區(qū)別

    這篇文章主要給大家介紹了關(guān)于JavaScript中setInterval()和setTimeout()用法及區(qū)別的相關(guān)資料,Javascript的setTimeOut和setInterval函數(shù)應(yīng)用非常廣泛,它們都用來處理延時(shí)和定時(shí)任務(wù),需要的朋友可以參考下
    2023-11-11

最新評論