Vue前端如何實現生成PDF並下載功能詳解

思路: 通過 html2canvas 將 HTML 頁面轉換成圖片,然後再通過 jspdf 將圖片的 base64 生成為 pdf 文件。

1. 安裝及引入

// 將頁面 html 轉換成圖片
npm install html2canvas --save  
// 將圖片生成 pdf
npm install jspdf --save

在項目主文件 main.js 中引入定義好的實現方法並註冊

import htmlToPdf from '@/utils/htmlToPdf';
// 使用 Vue.use() 方法就會調用工具方法中的install方法
Vue.use(htmlToPdf);

傳送門:Vue中 Vue.use() 原理及使用

2. 封裝導出 pdf 文件方法

配置詳解

let pdf = new jsPDF('p', 'pt', [pdfX, pdfY]);
第一個參數: l:橫向  p:縱向
第二個參數:測量單位("pt","mm", "cm", "m", "in" or "px");
第三個參數:可以是下面格式,默認為“a4”。如需自定義格式,隻需將大小作為數字數組傳遞,如:[592.28, 841.89];
		   a0 - a10
		   b0 - b10
		   c0 - c10
  		   dl
		   letter
		   government-letter
		   legal
		   junior-legal
		   ledger
		   tabloid
		   credit-card

pdf.addPage()  在PDF文檔中添加新頁面,默認a4。參數如下:

pdf.addImage()  將圖像添加到PDF。參數如下:

刪除某頁 pdf

let targetPage = pdf.internal.getNumberOfPages(); //獲取總頁
pdf.deletePage(targetPage); // 刪除目標頁

保存 pdf 文檔

pdf.save(`測試.pdf`);

封裝導出 pdf 文件方法(utils/htmlToPdf.js)

// 導出頁面為PDF格式
import html2Canvas from 'html2canvas'
import JsPDF from 'jspdf'
export default{
  install (Vue, options) {
    Vue.prototype.getPdf = function () {
      // 當下載pdf時,若不在頁面頂部會造成PDF樣式不對,所以先回到頁面頂部再下載
      let top = document.getElementById('pdfDom');
      if (top != null) {
        top.scrollIntoView();
        top = null;
      }
      let title = this.exportPDFtitle;
      html2Canvas(document.querySelector('#pdfDom'), {
        allowTaint: true
      }).then(function (canvas) {
        // 獲取canvas畫佈的寬高
        let contentWidth = canvas.width;
        let contentHeight = canvas.height;
	      // 一頁pdf顯示html頁面生成的canvas高度;
        let pageHeight = contentWidth / 841.89 * 592.28;
	      // 未生成pdf的html頁面高度
        let leftHeight = contentHeight;
	      // 頁面偏移
        let position = 0;
	      // html頁面生成的canvas在pdf中圖片的寬高(本例為:橫向a4紙[841.89,592.28],縱向需調換尺寸)
        let imgWidth = 841.89;
        let imgHeight = 841.89 / contentWidth * contentHeight;
        let pageData = canvas.toDataURL('image/jpeg', 1.0);
        let PDF = new JsPDF('l', 'pt', 'a4');
        // 兩個高度需要區分: 一個是html頁面的實際高度,和生成pdf的頁面高度
        // 當內容未超過pdf一頁顯示的范圍,無需分頁
        if (leftHeight < pageHeight) {
          PDF.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight)
        } else {
          while (leftHeight > 0) {
            PDF.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)
            leftHeight -= pageHeight;
            position -= 592.28;
            // 避免添加空白頁
            if (leftHeight > 0) {
              PDF.addPage();
            }
          }
        }
        PDF.save(title + '.pdf')
      })
    }
  }
}

相關組件中應用

<template>
  <div class="wrap" >
    <div id="pdfDom" style="padding: 10px;">
      <el-table
        :data="tableData"
        border>
        <el-table-column prop="date" label="日期" width="250"></el-table-column>
        <el-table-column prop="name" label="姓名" width="250"></el-table-column>
        <el-table-column prop="address" label="地址"></el-table-column>
      </el-table>
    </div>
    <button type="button" style="margin-top: 20px;" @click="btnClick">導出PDF</button>
  </div>

</template>
 
<script>
export default {
  data() { 
    return {
      exportPDFtitle: "頁面導出PDF文件名",
      tableData: [
         {
          date: '2016-05-06',
          name: '王小虎',
          address: '重慶市九龍坡區火炬大道'
        }, {
          date: '2016-05-07',
          name: '王小虎',
          address: '重慶市九龍坡區火炬大道'
        },{
          date: '2016-05-03',
          name: '王小虎',
          address: '上海市普陀區金沙江路 1518 弄'
        }, {
          date: '2016-05-02',
          name: '王小虎',
          address: '上海市普陀區金沙江路 1518 弄'
        }, {
          date: '2016-05-04',
          name: '王小虎',
          address: '上海市普陀區金沙江路 1518 弄'
        }, {
          date: '2016-05-01',
          name: '王小虎',
          address: '上海市普陀區金沙江路 1518 弄'
        }, {
          date: '2016-05-08',
          name: '王小虎',
          address: '上海市普陀區金沙江路 1518 弄'
        }, {
          date: '2016-05-06',
          name: '王小虎',
          address: '上海市普陀區金沙江路 1518 弄'
        }, {
          date: '2016-05-06',
          name: '王小虎',
          address: '上海市普陀區金沙江路 1518 弄'
        }, {
          date: '2016-05-07',
          name: '王小虎',
          address: '上海市普陀區金沙江路 1518 弄'
        }, {
          date: '2016-05-01',
          name: '王小虎',
          address: '上海市普陀區金沙江路 1518 弄'
        }, {
          date: '2016-05-08',
          name: '王小虎',
          address: '上海市普陀區金沙江路 1518 弄'
        }, {
          date: '2016-05-06',
          name: '王小虎',
          address: '上海市普陀區金沙江路 1518 弄'
        }, {
          date: '2016-05-07',
          name: '王小虎',
          address: '上海市普陀區金沙江路 1518 弄'
        }, {
          date: '2016-05-06',
          name: '王小虎',
          address: '南京市江寧區將軍大道'
        }, {
          date: '2016-05-07',
          name: '王小虎',
          address: '南京市江寧區將軍大道'
        },, {
          date: '2016-05-04',
          name: '王小虎',
          address: '上海市普陀區金沙江路 1518 弄'
        }, {
          date: '2016-05-01',
          name: '王小虎',
          address: '上海市普陀區金沙江路 1518 弄'
        }, {
          date: '2016-05-08',
          name: '王小虎',
          address: '上海市普陀區金沙江路 1518 弄'
        }, {
          date: '2016-05-06',
          name: '王小虎',
          address: '上海市普陀區金沙江路 1518 弄'
        }, {
          date: '2016-05-07',
          name: '王小虎',
          address: '上海市普陀區金沙江路 1518 弄'
        },{
          date: '2016-05-01',
          name: '王小虎',
          address: '上海市普陀區金沙江路 1518 弄'
        }, {
          date: '2016-05-08',
          name: '王小虎',
          address: '上海市普陀區金沙江路 1518 弄'
        }, {
          date: '2016-05-06',
          name: '王小虎',
          address: '上海市普陀區金沙江路 1518 弄'
        }, {
          date: '2016-05-08',
          name: '王小虎',
          address: '武漢市洪山區文化大道'
        }, {
          date: '2016-05-06',
          name: '王小虎',
          address: '武漢市洪山區文化大道'
        }, {
          date: '2016-05-07',
          name: '王小虎',
          address: '武漢市洪山區文化大道'
        }, {
          date: '2016-05-06',
          name: '王小虎',
          address: '南京市江寧區將軍大道'
        }, {
          date: '2016-05-07',
          name: '王小虎',
          address: '武漢市洪山區文化大道'
        },
      ]
    } 
  }, 
  methods: {
    btnClick(){
      this.$nextTick(() => {this.getPdf();})
    },
  },  
}
</script>  

效果

待優化部分

  1. 分頁時,頁面內容被截斷(歡迎留言討論交流);
  2. 不同內容,另起一頁開始;思路:計算超出內容,占最後一頁的高度(設定間距 =  頁面高度 – 超出部分高度)。

總結

到此這篇關於Vue前端如何實現生成PDF並下載功能的文章就介紹到這瞭,更多相關Vue前端生成PDF並下載內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: