javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > 前端打印分页PrintomJs

前端打印分页技术探讨与PrintomJs方案实现代码

作者:昼猫

这篇文章主要介绍了前端打印分页技术探讨与PrintomJs方案的相关资料,PritomJS通过手动和智能分处理策略来实现精确控制分页位置,处理文本、图片和表格、支持页眉页脚等功能,文中通过代码介绍的非常详细,需要的朋友可以参考下

一、问题背景

浏览器原生打印的局限:

要解决这些问题,通常的思路是:在打印前,手动把内容切分成一页一页。

二、市面上的常见方案对比

方案原理优点缺点
原生 window.print()直接调用浏览器打印简单、零依赖分页不可控、样式易丢失
CSS @media print用 CSS 控制打印样式标准方案、简单只能调样式,无法精确控制分页
page-break-* CSS 属性强制分页可控性比纯 CSS 强仅支持简单场景,表格/图片仍会断
html2canvas + jsPDF截图后转 PDF所见即所得,效果稳定性能差、文本不可选中、体积大
Print.js封装原生打印,增强样式处理简单易用分页能力有限
PrintomJs(本文方案)DOM 级手动分页 + 智能节点处理分页精确、保留可选文本、支持页眉页脚相对重一些

三、整体处理流程

┌─────────────────┐
│  原始 DOM 元素   │
└────────┬────────┘
         │
         ▼
┌─────────────────┐   预处理:
│   预处理阶段     │ → 克隆内容、移除 no-print
└────────┬────────┘ → 内联样式、打标记
         │
         ▼
┌─────────────────┐   分页(核心):
│   分页阶段       │ → 遍历节点、测量高度
└────────┬────────┘ → 判断溢出、处理策略
         │        → 文本截断/图片缩放/移页
         ▼
┌─────────────────┐   渲染:
│   渲染阶段       │ → 组装页面、加页眉页脚
└────────┬────────┘ → 挂载到预览容器
         │
         ▼
┌─────────────────┐
│  打印 / 预览     │
└─────────────────┘

四、关键技术点

1. 测高容器

这是分页系统的基础设施。它需要满足:

// 伪代码:创建测高容器
function createProbeContainer(pageConfig) {
  const container = document.createElement('div')
  container.style.cssText = `
    position: absolute;
    left: -9999px;
    top: 0;
    width: ${pageConfig.pageWidth}px;
    visibility: hidden;
  `
  document.body.appendChild(container)
  return container
}

2. 节点类型处理策略

不同类型的节点需要不同的处理策略:

节点类型处理方式
文本节点可截断,寻找合适的断点
图片不可截断,可缩放,或整页移
表格特殊处理,<thead> 每页重复
块级元素(div/p)整体判断,可递归检查子节点

3. 文本截断算法

文本截断是最复杂的部分。基本思路:

  1. 先判断整段文本是否溢出
  2. 如果溢出,用二分法寻找截断点
  3. 在词/句子边界处截断,避免半个字
// 伪代码:文本截断
function splitTextNode(textNode, remainingHeight) {
  const text = textNode.textContent
  let left = 0
  let right = text.length
  
  // 二分查找最大可容纳长度
  while (left < right) {
    const mid = Math.floor((left + right + 1) / 2)
    const part = text.slice(0, mid)
    const height = measureText(part)
    
    if (height <= remainingHeight) {
      left = mid
    } else {
      right = mid - 1
    }
  }
  
  // 尝试在标点/空格处回退,获得更自然的断点
  const breakPoint = findNaturalBreak(text, left)
  
  return {
    part1: text.slice(0, breakPoint),
    part2: text.slice(breakPoint)
  }
}

4. 图片缩放策略

图片处理需要权衡:是牺牲一点清晰度塞进当前页,还是留白移到下页?

通常的策略:

5. Hook 系统

实际项目中,用户往往需要在分页流程中插入自定义逻辑。一个设计良好的 Hook 系统能提供很大灵活性:

// 伪代码:Hook 系统
const hooks = {
  onBeforeParse(content) { /* 修改原始 DOM */ },
  onAfterParse(content) { /* 调整预处理结果 */ },
  onFilter(node) { /* 返回 false 跳过节点 */ },
  onBeforePageLayout(page, index) { /* 页面创建后 */ },
  onAfterPageLayout(page, index) { /* 页面填充后,可加水印 */ },
  onAfterChunked(pages) { /* 全部分页完成 */ }
}

五、PrintomJs 方案介绍

PrintomJs 是基于上述思路实现的一个零依赖打印库。

快速使用

import PrintomJs from 'printom-js'
import 'printom-js/print.css'

const printer = new PrintomJs({
  element: '#content',
  paper: 'A4',
  margin: 15,
  header: { right: '机密文件' },
  footer: { center: '第 {current} / {total} 页' }
})

await printer.exec()

主要特性

特性说明
智能分页DOM 级手动分页,表格/图片处理友好
页眉页脚支持 {current}/{total} 变量
纸张配置A3/A4/A5/Letter/Legal + 自定义尺寸
图片策略可配置缩放阈值,避免过度压缩
重复表头自动识别 <thead> 并每页重复
完整 Hooks15+ 个生命周期钩子

核心 API

// 创建实例
const printer = new PrintomJs(options)

// 预览
await printer.preview('#container')

// 打印
await printer.exec()

// 更新内容
document.getElementById('content').innerHTML = '新内容'
await printer.update()

// 销毁
printer.destroy()

六、总结

前端打印分页的核心挑战在于:

需要根据具体场景选择策略。但一个好的抽象(分阶段处理 + Hook 系统)能让解决方案更优雅、可扩展。

项目地址

GitHub: github.com/zhoumao1/Pr…

文档: zhoumao1.github.io/PrintomJs/

到此这篇关于前端打印分页技术探讨与PrintomJs方案实现的文章就介绍到这了,更多相关前端打印分页PrintomJs内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文