您的位置:  首页 > 技术 > 前端 > 正文

Vue中 前端实现生成 PDF 并下载

2021-10-08 19:00 OSCHINA CRMEB众邦科技 次阅读 条评论

思路: 通过 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);

复制代码

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. 不同内容,另起一页开始;思路:计算超出内容,占最后一页的高度(设定间距 = 页面高度 - 超出部分高度)。

如果你觉得这篇文章对你有点用的话,麻烦请给我们的开源项目点点star:http://github.crmeb.net/u/defu 不胜感激 !

  • 0
    感动
  • 0
    路过
  • 0
    高兴
  • 0
    难过
  • 0
    搞笑
  • 0
    无聊
  • 0
    愤怒
  • 0
    同情
热度排行
友情链接