Skip to content

打印与导出

Viewer 的打印和导出都建立在同一个前提上:页面已经通过 Viewer 渲染出来。

这一层不重新设计模板。它消费当前 Schema、数据、渲染页尺寸和页面 DOM。

浏览器打印

最短路径是直接调用 print()

ts
await viewer.print()

不传 driverId 时,Viewer 会走浏览器打印路径。即使你已经注册了自定义打印驱动,默认也仍然是浏览器打印。

有 Host 时,Viewer 会先给当前 Host 加一层打印隔离样式,再调用 host.print()。打印结束或抛错后,这层隔离状态会被清理。

纸张尺寸策略

pageSizeMode 用来回答一个问题:纸张尺寸听谁的。

ts
await viewer.print({ pageSizeMode: 'driver' })
await viewer.print({ pageSizeMode: 'fixed' })

当前只支持两个值:

  • driver:连续纸会让打印机驱动决定纸张;固定页仍会使用 Schema 解析出的纸张尺寸。
  • fixed:按 Schema 或已渲染页面尺寸生成固定纸张策略。

连续纸比较特殊。如果连续纸请求 fixed,Viewer 需要已经有渲染页尺寸。否则会发出 PRINT_RENDER_METRICS_MISSING 诊断。

自定义打印驱动

需要接本地服务、远程网关或专用设备时,注册一个打印驱动。

ts
viewer.registerPrintDriver({
  id: 'thermal-printer',
  defaults: {
    pageSizeMode: 'fixed',
  },
  async print(context) {
    console.log(context.printPolicy)
    console.log(context.renderedPages)
    console.log(context.container)
  },
})

await viewer.print({
  driverId: 'thermal-printer',
})

驱动可以提供 defaults.pageSizeMode。调用 viewer.print() 时,如果你没有显式传 pageSizeMode,Viewer 会使用驱动默认值。

context 里最常用的是:

  • schemadata
  • printPolicy
  • renderedPages
  • container
  • onPhaseonProgressonDiagnostic

驱动适合做协议适配。布局、分页和尺寸策略应该交给 Viewer 先算好。

自定义驱动可以复用 Viewer 传进来的任务回调。

ts
await viewer.print({
  driverId: 'thermal-printer',
  onPhase(event) {
    console.log(event.phase, event.message)
  },
  onProgress(event) {
    console.log(event.current, event.total)
  },
  onDiagnostic(event) {
    console.warn(event.code, event.message)
  },
  throwOnError: true,
})

throwOnError: true 会让打印驱动错误、打印策略错误或浏览器打印错误继续向外抛出。默认情况下,Viewer 会发诊断并结束这次打印调用。

导出器注册

导出使用 registerExporter()

ts
viewer.registerExporter({
  id: 'pdf-exporter',
  format: 'pdf',
  async export(context) {
    console.log(context.renderedPages)
    console.log(context.container)
    return new Blob(['ok'], { type: 'application/pdf' })
  },
})

然后调用 exportDocument()

ts
const blob = await viewer.exportDocument({
  format: 'pdf',
  entry: 'preview',
})

Viewer 会按 format 找到第一个匹配的导出器。如果不传 format,会使用当前实例注册的第一个导出器。

没有匹配导出器时,会发出 NO_EXPORTER 诊断。传了 throwOnError: true 时,同一个错误会继续抛出。

导出任务回调

导出器可以有 prepare(),也可以在 export() 里上报进度和诊断。

ts
const blob = await viewer.exportDocument({
  format: 'pdf',
  entry: 'api',
  onPhase(event) {
    console.log(event.phase)
  },
  onProgress(event) {
    console.log(event.current, event.total)
  },
  onDiagnostic(event) {
    console.warn(event.code, event.message)
  },
  throwOnError: true,
})

当前 Viewer 会在导出过程中发出这些阶段:

  • prepare() 时:preparing
  • 调用 export() 前:exporting
  • 导出成功后:completed

如果导出器抛错,Viewer 会发出 EXPORTER_ERRORthrowOnError: true 时会继续抛出原始错误。

字符串快捷调用

exportDocument() 也可以直接传格式字符串。

ts
const blob = await viewer.exportDocument('pdf')

这等价于:

ts
const blob = await viewer.exportDocument({
  format: 'pdf',
  entry: 'api',
})

如果你的导出来自预览按钮、保存菜单或程序调用,可以显式传 entry。当前类型支持 save-menupreviewapi

打印策略解析

写驱动时,你通常会想知道 Viewer 最终准备怎么打印。

ts
import { resolvePrintPolicy } from '@easyink/viewer'

const policy = resolvePrintPolicy({
  schema: documentSchema,
  options: { pageSizeMode: 'fixed' },
  renderedPages: viewer.renderedPages,
})

策略对象里常用字段是:

  • pageMode
  • pageSizeMode
  • sheetSize
  • orientation
  • pageBreakBehavior
  • offset

sheetSize.source 会告诉你尺寸来自 schema 还是已渲染页面。

PDF 导出路径

Viewer 本身只定义导出器接口,不内置 PDF 导出实现。

ts
viewer.registerExporter({
  id: 'pdf-exporter',
  format: 'pdf',
  async export(context) {
    const pages = Array.from(
      context.container?.querySelectorAll<HTMLElement>('.ei-viewer-page') ?? [],
    )

    return renderPdfSomehow(pages, context.renderedPages ?? [])
  },
})

如果你要使用官方 DOM 转 PDF 插件,继续看 自定义导出插件。如果你要把 Viewer 接到打印设备,继续看 自定义打印驱动

关于打印与导出,目前知道这些就够用了。排查错误时可以继续看 诊断系统