html生成pdf--print-js,保存下载到本地,可选中复制,且解决font-size不生效问题

背景

之前有需求,一键生成pdf,下载到本地,详见;http://t.csdn.cn/5GzSx。
本次的需求基于上次有升级,上次是直接生成pdf,只是为了看。这次的需求是预览账单并保存为pdf,保存的pdf是可以选中复制的,那么之前的方案就不能用了。

调研

网上有很多方法,但是都或多或少存在问题,大部分的都是先生成图片,然后再生成pdf文件。不可复制,还容易失真。后面尝试了多种方式后,发现了一个宝藏,直接利用浏览器的打印功能。一语点醒梦中人呀,不仅可以预览,还可以保存为pdf,还可以选中复制。
html生成pdf--print-js,保存下载到本地,可选中复制,且解决font-size不生效问题_第1张图片
后面尝试了写一写,发现存在一些兼容问题和样式问题,而且需要处理选定固定的dom去保存。基于此,去调研了一下,找到一个比较好用的库,兼容性挺好,样式也能保留。— print-js:https://printjs.crabbly.com/

  • 直接使用window.print,中间将我们需要打印的dom替换body,样式有问题,而且,在点击预览之前,我页面其实是没有渲染的,这样替换,会导致我页面的变化。
const print = () => {
  let printHtml = printRef.value.innerHTML 
  let oldHtml = window.document.body.innerHTML
  window.document.body.innerHTML = printHtml
  // 调用打印功能
  window.print()
  window.document.body.innerHTML = oldHtml 
  return false
}
  • 使用iframe 这会丢掉我们写的css样式,但是style的没有丢。还可能存在兼容性问题
const print = () => {
 let iframe = document.getElementById('print-iframe')
 // 防止多次重建iframe
  if (!iframe) {
    var el = document.getElementById('print-content')
    iframe = document.createElement('IFRAME')
    var doc = null
    iframe.setAttribute('id', 'print-iframe')
    iframe.setAttribute('style', 'position: absolute; width: 0px; height: 0px;left:-500px;top:-500px;')
    document.body.appendChild(iframe)
    doc = iframe.contentWindow.document
    // 这里可以自定义样式
    doc.write('') // 解决出现页眉页脚和路径的问题
    doc.write('
' + printHtml + '
'
) doc.close() iframe.contentWindow.focus() } setTimeout(function () { iframe.contentWindow.print() }, 50) // 解决第一次样式不生效的问题 if (navigator.userAgent.indexOf('MSIE') > 0) { document.body.removeChild(iframe) } }

print-js使用

看了一下源码,实际使用的还是iframe方式,里面做了很多兼容

import print from 'print-js'
  print({
    printable: 'print-content',
    // header: '账单',
    type: 'html',
    // maxWidth: 800,
    // headerStyle: 'font-size:6px;font-weight:600;text-align:center;padding:15px 0 10px 0;',// 标题设置
    // properties: [],// json数据元
    // gridHeaderStyle: 'font-size:6px;font-weight:400;height:40px;line-height:40px;border: 1px solid #ccc;padding:3px 5px 3px 5px;text-align:center;',// json格式表头样式
    // gridStyle: 'font-size:1px;font-weight:200;border: 1px solid #ccc;padding:3px 5px 3px 5px;text-align:center;',// json各式表哥央视
    // scanStyles: false,// 不适用默认样式
    // repeatTableHeader: false,// 打印json表头只显示在第一页
    // style: '@page{size:auto;margin: 0cm 1cm 0cm 1cm;}',// 去除页眉页脚
    // font_size: 30,
    targetStyles: ['*'], // 使用dom的所有样式,很重要
    ignoreElements: ['no-print','bc','gb']
  })

因为我的页面最开始对账单是不显示的,状态是’display: none’,预览打印出来的就是空白,解决办法:在打印前后处理dom状态

const dom = document.getElementById('print-content')
dom?.setAttribute('style', 'display: block') 
// ... 调用打印
dom?.setAttribute('style', 'display: none') 

  • 我们在css中写的font-size不起作用,查看源码才知道,它代码里面写死了,还写了important
    在这里插入图片描述
    百度了解决办法,有降低版本的,有手动修改node_moudles文件的(这上线不也凉凉),然后我发现它取的params中的font_size,而且还有默认值,所以我就想,那我传个‘’不就好了 font_size: ‘’。到了dom上,font-size: !important; 也是个无效的样式,这样就不会覆盖我本来的样式了。

完整代码

import print from 'print-js'
const handlePrint = () => {
  const dom = document.getElementById('print-content')
  dom?.setAttribute('style', 'display: block') 
    print({
      printable: 'print-content',
      // header: '账单',
      type: 'html',
      // maxWidth: 800,
      // headerStyle: 'font-size:6px;font-weight:600;text-align:center;padding:15px 0 10px 0;',// 标题设置
      // properties: [],// json数据元
      // gridHeaderStyle: 'font-size:6px;font-weight:400;height:40px;line-height:40px;border: 1px solid #ccc;padding:3px 5px 3px 5px;text-align:center;',// json格式表头样式
      // gridStyle: 'font-size:1px;font-weight:200;border: 1px solid #ccc;padding:3px 5px 3px 5px;text-align:center;',// json各式表哥央视
      // scanStyles: false,// 不适用默认样式
      // repeatTableHeader: false,// 打印json表头只显示在第一页
      // style: '@page{size:auto;margin: 0cm 1cm 0cm 1cm;}',// 去除页眉页脚
      font_size: '', // 解决本来的font-size 不生效问题
      targetStyles: ['*'], // 使用dom的所有样式,很重要
      ignoreElements: ['no-print','bc','gb']
    })
    dom?.setAttribute('style', 'display: none') 
}

你可能感兴趣的:(html,pdf,前端)