前端套打和打印插件hiprint实践附带源码解读

4,003 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第26天,点击查看活动详情 >>

前言

在做一些toB的项目的时候,单据打印和套打是必须要具备的一项功能,接下来我就以我在项目中的实践为例,讲解hiprint在vue中的用法以及源码内的实现。

官方文档地址:http://hiprint.io/

目录结构

    hiprint/
    ├── css/
    │   ├── hiprint.css
    │   ├── print-lock.css
    ├── plugins/
    │   ├── JsBarcode.all.min.js
    │   └── qrcode.js
    │   └── jquery.minicolors.min.js
    │   └── jquery.hiwprint.js
    ├── hiprint.bundle.js
    ├── polyfill.min.js

从官网下载的hiprint解压后目录结构是这样的,我们需要引入对应的css,polyfill要看你的webpack配置,如果配置了,就无须引入了,plugin可以用external的方式以cdn的形式引入,核心文件就是hiprint.bundle.js,他提供了设计与解析页面。

使用

使用时,我们只需要以import的方式,将hiprint对象引入进来

import hiprint from 'xxx/hiprint/hiprint.bundle.js'

然后调用他的初始化方法init

// 初始化打印插件
hiprint.init({
    providers: [new DefaultElementTypeProvider()]
})

注意看下图,init方法是将 传入的配置与原先的配置通过$.extend做了合并,也就是说,这里init直接什么也不传都是可以的。我这里就是重新定义了一下页面上的元素类型 image.png

image.png

接下来就是解析模版,主要看下图,主要是用到了PrintElementTypeManager,PrintTemplate方法

image.png

  • PrintElementTypeManager 定义哪些作为设计元素,这里我们是定义了所有包含ep-draggable-item这个类名的作为设计元素,响应拖拽,每个ep-draggable-item上通过自定义属性tid标识是哪种设计元素
<a class="ep-draggable-item" tid="defaultModule.text" style>
  <span
    class="glyphicon glyphicon-text-width"
    aria-hidden="true"
  ></span>
  <p class="glyphicon-class">文本</p>
</a>
  • PrintTemplate 定义当前打印页面的模板是什么,template定义的是打印的模板json,settingContainer配置对象的dom id,paginationContainer分页对象的dom id,hiprintTemplate.design 是定义设计器的dom id
self.hiprintTemplate = new hiprint.PrintTemplate({
  template: _customPrintJson,
  settingContainer: '#PrintElementOptionSetting',
  paginationContainer: '.hiprint-printPagination'
})
// console.log(this.hiprintTemplate.getJson())
// 打印设计
self.hiprintTemplate.design('#hiprint-printTemplate')
self.setCurrentPaper(self.paperMap.A4)
self.elementAddEventListen()

自定义事件是通过hiprint挂在全局的hinnn对象上的event去分发的 image.png

image.png

然后,你就能看到页面了

image.png

核心方法

  • px-pt 互转

1pt = 1px * 72 / dpi

1px = 1pt / 72 * dpi

(hinnn.pt = {
        toPx: function toPx(t) {
          return t * (this.getDpi() / 72);
        },
        dpi: 0,
        getDpi: function getDpi() {
          if (!this.dpi) {
            var _t2 = document.createElement("DIV");

            (_t2.style.cssText =
              "width:1in;height:1in;position:absolute;left:0px;top:0px;z-index:99;visibility:hidden"),
              document.body.appendChild(_t2),
              (this.dpi = _t2.offsetHeight);
          }

          return this.dpi;
        }
      }),
      (hinnn.px = {
        toPt: function toPt(t) {
          return t * (72 / this.getDpi());
        },
        dpi: 0,
        getDpi: function getDpi() {
          if (!this.dpi) {
            var _t3 = document.createElement("DIV");

            (_t3.style.cssText =
              "width:1in;height:1in;position:absolute;left:0px;top:0px;z-index:99;visibility:hidden"),
              document.body.appendChild(_t3),
              (this.dpi = _t3.offsetHeight);
          }

          return this.dpi;
        }
      }),
  • mm转pt/px
(hinnn.mm = {
    toPt: function toPt(t) {
      return (72 / 25.4) * t;
    },
    toPx: function toPx(t) {
      return hinnn.pt.toPx(hinnn.mm.toPt(t));
    }
  }),
  • toPng

这里,他页面的css单位是mm,所以需要先把毫米转为pt, 然后再把页面上的svg转为了image,拿到页面完整的html,并通过html2canvs方法,转成图片,然后调用系统的window.print方法,将图片进行打印。 image.png

  • toPdf

这里和toPng大同小异,也是先转为pt,然后通过jsPDF插件将页面转成pdf,然后通过html2canvas先把页面转成图片,然后再把图片添加到pdf实例内,最终返回pdf实例 image.png

image.png

结语

hiprint 插件上手简单,兼容性也不错,转图片的性能也还可以,针对html2canvas和jspdf的配置也都是经过了作者调优的options,可以说是开箱即用,非常简单,源码虽然经过混淆,但是大部分变量都还在,经过一段时间阅读也能对源码进行有限修改以适配项目需求,建议有页面打印单据需求的同学可以调研一下这个插件