前端将md文件转成pdf

最近做了一个功能,将md文档转成pdf发送给客户。偶有心得总结如下:

使用html-pdf

1号选手

  • 优点: 简单易懂,非常方便
  • 缺点: 不是很灵活,不方便添加目录,分页,样式处理等等

使用方法简便主要如下:

const pdf = require('html-pdf');
const fs = require('fs');
const moment = require('moment'); // moment.js
const html = fs.readFileSync('../public/pdfs/test.html', 'utf8'); 

const createPDFProtocolFile = function (template, options, reg, filename) {
  if (reg && Array.isArray(reg)) {
    reg.forEach(item => {
      template = template.replace(item.relus, item.match);
    });
  }
  pdf.create(template, options).toFile(filename, function(err, res) {
      if (err) {
          return console.log(err);
      }
      console.log(res);
  });
}

createPDFProtocolFile(html, options, reg, './test.pdf'); // 传入参数 生成pdf

配置规则如下:

const options = {
    "format": 'A4',
    "header": {
    "height": "10mm",
    "contents": ''
}}; // 一些配置
const name = '张三';
// 匹配规则
const reg = [
  {
    relus: /__name__/g,
    match: name
  },
  {
    relus: /__date__/g,
    match: moment().format('YYYY年MM月DD日')
  }
];

此方法非常便利,但是如此便利方法有很多局限性,比如内部锚点无法跳转,无法根据标题生成目录,无法根据目录完成跳转,无法在页眉页角添加公司logo,无法做到多篇文章导出一个pdf时候分页等等。你所能使用的技术太少。所以需要用另一种框架。

wkhtmltopdf框架

这是一个非常不错的框架,比较轻便。当然也有很多坑。具体使用有两种方式,一种直接使用命令行,简单易懂,需要的小伙伴请参考官方文档,由于前端本身限制,此方法不可行。这里我们着重讲一下第二种方式,基于前端实现。

  1. 使用前需要搭建一个wkhtmltopdf的运行环境,具体操作参照官网
  2. 【官网】:【http://wkhtmltopdf.org/】

    【下载请点击这里】 【http://wkhtmltopdf.org/downloads.html】

  3. 需要引用node包,npm i wkhtmltopdf

  4. 代码编写如下:

    const wkhtmltopdf = require('wkhtmltopdf')
    const { pdfCss } = require('./pdfcss/css')
    const { readdirSync, statSync, existsSync, readFileSync, writeFileSync } = require('fs')
    const { join } = require('path')
    const { mkdir } = require('./helper/file')
    
    
    
    const setPdf = (urls) => {
        contents = ''
        mkdir(targetPdf)
        const fileName = targetPdf + '/' + arr[1] + '-' + arr[2] + '-' + arr[3] + '.pdf' // 文件名称
        wkhtmltopdf(contents, {output: fileName})
    }

    当然这是最基础版本,下面我们来看一下坑位

    wkhtmltopdf(contents, {output: fileName, headerHtml, footerHtml: targetPdfFooter + '/footer.html', headerLine: true, footerLine: true, headerSpacing: 3, ignore: [
          'Exit with code 1 due to network error: ProtocolUnknownError\n',
          'wkhtmltopdf exited with code 1'
        ]})

    此坑位是一个错误兼容处理,如果你导出的文件量比较多,这时候内容会导出,但是在运行到Jenkins等自动部署工具中会有编译错误,所以需要添加一个ignore忽略错误。

  5. 页眉编辑

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <style>
        img {
          height: 40px;
          vertical-align: bottom;
          float: left;
          margin-left: -10px;
        }
        span {
          line-height: 35px;
          float: right;
        }
        div {
          height: 40px;
        }
      </style>
    </head>
    <body>
      <div><img src="https://logo-h.png"/><span>音视频通话</span></span></div></body></html>

    页眉可以自定义,但是添加公司logo图片时候不能是本地地址,需要可访问地址,内容中的图片做了同样处理。

  6. 页脚编辑

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <style>
        p {
          text-align: right;
          line-height: 30px;
        }
        .span-lf {
          float: left;
        }
      </style>
    </head>
    <script type="text/javascript"> 
      function substitutePdfVariables() { 
    
        function getParameterByName(name) { 
        var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search); 
        return match && decodeURIComponent(match[1].replace(/\+/g, ' ')); 
        } 
    
        function substitute(name) { 
        var value = getParameterByName(name); 
        var elements = document.getElementsByClassName(name); 
    
        for (var i = 0; elements && i < elements.length; i++) { 
          elements[i].textContent = value; 
        } 
        } 
    
        ['frompage', 'topage', 'page', 'webpage', 'section', 'subsection', 'subsubsection'] 
        .forEach(function(param) { 
          substitute(param); 
        }); 
      } 
      </script> 
    </head> 
    <body onload="substitutePdfVariables()"> 
      <p>第 <span class="page"></span> 页  共 <span class="topage"></span> 页<span class="span-lf"></span></p> 
    </body> 
    </html>

    页脚中做了分页处理

  7. 样式分页

    @media screen{
      div.break_here {
        page-break-after: always !important;
      }
    }

    在每个文章结尾处需要添加一个分割标签,标签类样式break_here

  8. 标题整理,wkhtmltopdf可以根据h标签自动生成目录,所以小伙伴们需要在编写时对标题进行规范

  9. `不能出现在内容中,如果有需要在用正则替换,此方法耗时耗力,但是么有更高手段如果有好的方法希望小伙伴多多交流

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值