jspdf + html2canvas 開發前端pdf導出功能記錄

目錄

插件

實現

簡單分頁

進一步分頁

關於html2canvas的一點小經驗


最近在開發項目的時候,接到了一個需求。聽起來是比較簡單的,將後臺系統的報表以pdf文件的形式導出。excel導出,圖片導出都做過了,現在輪到pdf了。在實現的過程中遇到了一些困難,通過查閱資料,網上各位朋友使用過的經驗後,差不多完成。寫這篇博客希望將自己的經驗留下,幫助到更多的朋友。

插件

PDF類

  1. pdfmake  官網地址: https://pdfmake.github.io/docs/getting-started/

  2. jspdf  官網地址: http://raw.githack.com/MrRio/jsPDF/master/docs/index.html

DOM轉化爲Canva

     1. html2canvas  官網地址: http://html2canvas.hertzen.com/getting-started

 

實現

最初我是想使用pdfmake來自定義報告表單的,無奈自定義起來太麻煩,比如一些合併單元格的操作需要花費太多時間去研究,後面直接轉投pdf,原因還是覺得jspdf與html2canvas直接轉換圖片使用起來比較快,直接把圖片放入pdf即可。

先根據網址進到每個插件中,選擇適當的方法將插件下載下來。接下來直接開擼代碼,話不多說,貼上測試代碼。

 

簡單分頁

下面試簡單的將一個指定的表格轉換爲pdf,包含了最簡單的分頁。

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>PDF導出測試</title>
    <style>
        * {
            margin: 0;
        }

        .container {
            height: 400px;
            overflow-y: auto;
        }

        .content {
            margin-top: 20px;
        }

        table {
            border-collapse: collapse;
            font-size: 16px;
            width: 80%;
            margin: 0 auto;
            word-break: break-all;
        }

        td {
            padding: 5px;
            border: 1px solid;
            text-align: center;
        }
    </style>
</head>
<script src="./js/html2canvas.min.js"></script>
<script src="https://unpkg.com/jspdf@latest/dist/jspdf.min.js"></script>

<body>
    <div>
        <button onclick="getContent()">導出PDF</button>
    </div>
    <div class="container">
        <div class="content">
            <table>
                <tr>
                    <td>報告</td>
                    <td>結果</td>
                    <td>數值</td>
                    <td>數值</td>
                    <td>數值</td>
                    <td>數值</td>
                    <td>數值</td>
                </tr>
                <tr>
                    <td>1</td>
                    <td>2</td>
                    <td>3</td>
                    <td>3</td>
                    <td>3</td>
                    <td>3</td>
                    <td>3</td>
                </tr>
            </table>
        </div>
    </div>
</body>
<script src="../pdfmake/build/vfs_fonts.js"></script>
<script>
    // 增加測試數據
    function addTr() {
        const table = document.querySelector('table');
        const tr = document.querySelectorAll('tr')[1];
        for (let i = 1; i < 100; i++) {
            var nTr = document.createElement('tr');
            nTr.innerHTML = tr.innerHTML;
            table.appendChild(nTr);
        }
    }
    addTr();



    function getContent() {
        const content = document.querySelector('.content'); // 獲取待導出的pdf內容DOM
        const rect = content.getBoundingClientRect(); // 獲取pdf內容DOM的位置
        var pdf = new jsPDF('', 'pt', 'a4') // 初始化jspdf對象
        generatePDF(content, pdf, rect);

    }

    function generatePDF(content, pdf, rect) {
        console.log(rect.top);
        const op = {
            scale: 1,
            logging: true,
            width: Number(getComputedStyle(content).width.replace('px', '')), // 設置畫布的寬度
            height: Number(getComputedStyle(content).height.replace('px', '')) // 設置畫布的高度
        };

        html2canvas(content, op).then(
            canvas => {
                const data = canvas.toDataURL('png', 1);  // 將生成的canva轉換爲base64
                var imgWidth = 595.28; // 設置圖片在pdf中寬度
                var imgHeight = 592.28 / canvas.width * canvas.height; //設置圖片在pdf中的高度
                var singlePdfHeight = 841.89; // pdf單頁的高度
                var singlePageHeight = canvas.width / 592.28 * 841.89; // A4紙單頁高度在canvas中對應的高度
                var position = 0; //每一頁pdf偏移量
                var leftHeight = canvas.height; // 剩餘高度
                if (leftHeight < singlePageHeight) {
                    // 如果canvas圖片總高度比pdf單頁高度小可直接生成圖片
                    pdf.addImage(data, 'PNG', 0, 0, imgWidth, imgHeight);
                } else {
                    // 如果canvas圖片總高度比pdf單頁高度大, 循環生成pdf
                    while (leftHeight > 0) {
                        pdf.addImage(data, 'PNG', 0, position, imgWidth, imgHeight);
                        leftHeight -= singlePageHeight;
                        position -= singlePdfHeight;
                        if (leftHeight > 0) {
                            pdf.addPage(); // 若一頁高度無法顯示完整個內容,增加新一頁Pdf
                        }

                    }
                }

                pdf.save("content.pdf");
            }
        );
    }


</script>

</html>

進一步分頁

這裏我就提供一下思路:

那這個table表格做列子, 可以通過單頁A4紙換算到html的高度,然後根據這個高度將html中要截取的內容進行分割。最後分割爲幾部分就有幾頁即調用幾次html2canvas。 通過調整html2canvas配置中的y參數來達到分頁效果。

 

關於html2canvas的一點小經驗

這裏要提一個關於html2canvas生成的canvas中內容偏移量的問題。 你有可能遇到使用html2canvas得到的內容與自己的預期不一致,想要明白爲什麼主要要搞清楚html2canvas的默認配置。

假設你要截取的html內容塊的外層DOM爲  warpper

const warpper = document.querySelector('.warpper');

option {

   scale: 默認值爲window.devicePixelRatio--如果你不設置值可能會導致你的canvas畫布比實際設置的值偏大

   y:  默認值爲 wapper.getBoundingClientRect().top + window.pageYOffset 

   x:  默認值爲 wapper.getBoundingClientRect().left + window.pageXOffset 

}

 

在官方文檔中,我沒有找到對y的默認值,翻看源碼後才發現。所以我在開發過程中相同的代碼,不同的樣式中可能得到的效果不一樣。因此根據源碼中的默認值爲基礎來調整canvas中內容偏移位置,得到你想要的效果。

比如想要設置縱向上的偏移量,要注意window.pageYOffset是否考慮進去。

希望可以幫助到各位,如果文中有問題的地方歡迎大家留言一起討論。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章