vue实现打印PDF功能 - html2Pdf.js

踩坑预警

最近更新已经三年前的事情了,将近四百多个问题还未close(重复的问题也挺多的) 官网地址

安装操作

js 复制代码
npm install --save html2pdf.js 
or
npm install --save html2pdf.js -- force
or
cnpm install --save html2pdf.js 

实现直接下载保存PDF操作

可以通过html布局好了,直接打印下载

js 复制代码
import html2pdf from 'html2pdf.js';
let tableElement = document.querySelectorAll('table')
html2pdf().from(tableElement).save(filename);

踩坑历程

要求: 我这边是纯表格的打印操作,但是要求是分页的时候每个表格都是需要携带表头,表格内的图片需要展示

踩坑一: 网络图片无法展示

翻阅了源码开发者上别人提的Issues中发现,这玩意html2canvas处理的时候只能支持base64,虽然有人说可以配置 html2canvas: {scale: 2, useCORS: true},可以解决【但是我测试不行,开发者提议使用base64】

js 复制代码
let imageUrl = 'https://www.baidu.com/img/flexible/logo/pc/result.png'
let image = new Image();
//解决跨域问题
image.setAttribute('crossOrigin', 'Anonymous');
image.src = imageUrl
//image.onload为异步加载
let base64Datas = []
image.onload = () => {
    var canvas = document.createElement("canvas");
    canvas.width = image.width;
    canvas.height = image.height;
    var context = canvas.getContext('2d');
    context.drawImage(image, 0, 0, image.width, image.height);
    var quality = 0.8;
    //这里的dataurl就是base64类型
    var dataURL = canvas.toDataURL("image/jpeg", quality);//使用toDataUrl将图片转换成jpeg的格式,不要把图片压缩成png,因为压缩成png后base64的字符串可能比不转换前的长!
    //数组存放图片base64
    base64Datas.push(dataURL);
    //递归执行图片url转base64        
}

踩坑二: 表头没办法在分页后的自动携带上(printJS这个插件就相当不错,可太傲娇)

这个也是我搞了好久的地方,一开始在Issues中发现添加页码的方式想法去添加表头,如

js 复制代码
 html2pdf().from(tableElement).set(options).toPdf().get('pdf').then(function (pdf) {
    console.log(pdf)
    // paf.table({html: thead})
  }).save(filename);

,then做PDF的操作,打印PDF暴露出来的API方法中改哪个都油盐不进,一点变化都没有,放弃了,运用固定住表格里的数据高度固定,动态去插入表头进去每个数据中,实现现有表头功能

javascript 复制代码
 const clonedThead = tableElement.querySelector('thead').innerHTML;
  let tbodyList = tableElement.querySelectorAll('tbody');
  console.log(tbodyList)
  tbodyList.forEach((item,index) => {
    if( index % 5 === 0 && index > 0) {
      item.insertAdjacentHTML('afterbegin', '<div style="padding-top: 20px">'+clonedThead+'</div>');
    }
  })

踩坑三: 分页出现截断内容

  1. 配置options 解决分页问题:
javascript 复制代码
const options = {
    margin: 10,
    html2canvas: { 
      scale: 2 
    },
    jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait'},
    pagebreak: {  mode: ['avoid-all', 'css', 'legacy'] },
}
  1. 样式控制

page-break-inside: avoid 可以保留完整的页面

page-break-before: always 可以另起新的一页

从源码发现可以添加类 html2pdf__page-break 进行换页

css 复制代码
//对表格内容保持完整性
.td {
    min-width: 60px;
    text-align: center;
    word-wrap: break-word;
    word-break: break-all;
    border: 1px solid #000;
}

3. 浑身解数之后发现还是会保留一点第二页的数据在第一页中,这种情况有可能是html2canvas画的canvas和设置的A4纸的大小有关了

解决: 我这边运用了插入表头的时候增加个paddingTop的高度可以解决

printJS 打印使用

挺好用的,以上的要求基本能符合需求的开发要求,可惜开源博主在Issues中说我只专注打印开发,如果需要直接下载可以用别的插件很好支持,这边就专注于打印功能。 很显然有点满足不了我多表格区分下载的实现。他这个只支持于单个pdf导出打印预览,有实现过的小伙伴欢迎评论给出兼容的解决方案【【根据HTML可解决直接下载多个PDF】】

javascript 复制代码
// 与html2Pdf.js 区别在的是样式需要单独配置进插件中,无法识别html里的样式,
// 如果需要分页可以根据踩坑三中的样式控制操作,并且图片无需转成base64,
// 我要处理的图片出现跨域问题,在这个插件是不存在这个问题,直接自动处理网络图片
// 附上实现方案
setTimeout(() => {
    printJS({
      printable: 'print', // 要打印的id
      type: 'html',
      header: '',
      style: `@page{size:auto;margin: 0cm 1cm 0cm 1cm;}
      .store-img-stock {
        display:block;
        padding:20px;
        width: 260px;
        height: 260px;
      }
      .s-placeholder{ visibility: hidden; }
      @media print {
        body {
          -webkit-print-color-adjust: exact;
          -moz-print-color-adjust: exact;
          -ms-print-color-adjust: exact;
          print-color-adjust: exact;
        }
      }
      .hidden-border-bottom {
        border-bottom: none;
        border-top: none;
      }
      .thead-th {
        background-color: #333586 !important;
        color: #fff !important;
      }
      .empty-height {
        max-height: 50px;
      }
      .height-20 {
        height: 16px;
      }
      .store-table-a1 {
        margin-bottom: 20px;
        page-break-before: always;
      }
      .store-table-a1 td {
        min-width: 60px;
        text-align: center;
        word-wrap: break-word;
        word-break: break-all;
        border: 1px solid #000;
      }
      .store-table th {
        height: 35px;
        border: 1px solid #000;
      }
      .hidden-border {
        border: none !important;
      }
      ` // 去除页眉页脚
    })
  }, 500)
相关推荐
brzhang5 小时前
我操,终于有人把 AI 大佬们 PUA 程序员的套路给讲明白了!
前端·后端·架构
止观止5 小时前
React虚拟DOM的进化之路
前端·react.js·前端框架·reactjs·react
goms5 小时前
前端项目集成lint-staged
前端·vue·lint-staged
谢尔登5 小时前
【React Natve】NetworkError 和 TouchableOpacity 组件
前端·react.js·前端框架
Lin Hsüeh-ch'in6 小时前
如何彻底禁用 Chrome 自动更新
前端·chrome
augenstern4167 小时前
HTML面试题
前端·html
张可7 小时前
一个KMP/CMP项目的组织结构和集成方式
android·前端·kotlin
G等你下课8 小时前
React 路由懒加载入门:提升首屏性能的第一步
前端·react.js·前端框架
蓝婷儿9 小时前
每天一个前端小知识 Day 27 - WebGL / WebGPU 数据可视化引擎设计与实践
前端·信息可视化·webgl
然我9 小时前
面试官:如何判断元素是否出现过?我:三种哈希方法任你选
前端·javascript·算法