封装打印组件

Vue打印组件封装-每页签名表格实现

#tech / dev / frame #type / howto #status / growing

封装打印组件

背景说明

现在打印内容有 正文 + 签名表格(应该每页都完整显示)

当前使用将 正文+表格都放在一起,使用 html2CanvasPrint 将 DOM 渲染为一个画布 然后调用浏览器打印方式来打印,会自动翻页(正文内容较多时,表格分割并且不是每页都有)

现在的打印实现逻辑: 点击按钮,跳转到 printDetail 页面并携带参数(用于获取数据),然后渲染页面

所以我只需要 提取 function 获取数据、 function 获取签名表、 function 渲染数据表格、 function 渲染签名表格、 function 渲染 分页PDF、const printCss、

目标:

  • 签名表格不跨页拆分。
  • 确保每页都有完整的签名区域。
  • 先在页面底部放签名表(重复显示内容),剩余空间来渲染 其余内容

解决方案选项:

  1. 基于 DOM 的打印 + CSS 分页控制(推荐)
  • 停止转换为画布,直接打印 DOM。
  • 使用支持 CSS 的打印库:
    • 为签名表格容器添加 page-break-inside: avoid; break-inside: avoid-page
    • 调整内容结构,使每页包含 “主表格片段” 和签名区块。
  • 优点:通过 CSS 实现更精细控制;可实现每页重复签名区域。
  • 缺点:需手动将 archiveList 分页拆分。
  1. 手动分页 + 每页独立容器(可靠)
  • 按每页行数拆分 archiveList(例如每页 15 行,可根据布局调整)。
  • 为每页渲染:
    • 页眉
    • 包含当前页数据的子表格
    • 签名表格(appendix-1 和 appendix-2
    • 备注框(可选是否每页显示)
  • 为每个页面容器添加 page-break-after: always; 及 page-break-inside: avoid CSS。
  • 可确保签名表格不拆分且每页均显示。
  • 优点:结果可预测;布局一致性强。
  • 缺点:需一定开发工作量;每页行数需根据 A4 尺寸调整。
  1. 画布切片(若坚持使用 html2canvas 的备选方案)
  • 按当前 DPI 计算 A4 页面对应的画布高度,将长画布切片为多张图片,确保签名区块不被切割。
  • 需计算签名区块的 Y 轴位置并调整切片边界。
  • 优点:保持图片打印模式。
  • 缺点:逻辑复杂;对动态内容适应性差;需测量 DOM 以对齐切片位置。

优选方案:2) 手动分页 + 直接 DOM 打印 + 分页控制 CSS

vue-print-next 是否适用?

  • 概述:vue-print-next 库专注于打印特定 DOM 元素,提供钩子函数、样式注入和配置项,依赖原生打印或 iframe 实现,而非画布。
  • 适用性:
    • 支持直接打印 DOM 内容,可识别 CSS 分页符(page-break-insidebreak-insidepage-break-after)。
    • 可将每页内容封装为独立元素,确保签名表格不拆分。
    • 可通过在每个页面容器中渲染页眉 / 页脚类区块,实现每页重复显示。
  • 限制:
    • 浏览器对 “运行时页眉 / 页脚” 的支持不一致。仅通过 CSS 无法实现签名区域自动作为每页页脚重复显示,需在 DOM 中为每页单独渲染签名表格。
    • vue-print-next 不支持自动分页 —— 需手动拆分 archiveList
  • 结论:适用。若实现手动分页并配置正确 CSS,vue-print-next 可实现基于 DOM 的打印,确保每页签名区域完整无拆分。

vue-print-next

实现

Q1

打印界面不能翻页,只显示第一页

使用如下代码解决了

<style>
/* 强制覆盖全局的 html/body 样式,确保打印时可以滚动/分页 */
@media print {
  html, body, #app {
    height: auto !important;
    overflow: visible !important;
    display: block !important;
  }
}
</style>

Q2

预览界面不能翻页,只显示第一页

Q3

页面样式需要调整,

  1. 让 签字表 始终位于最下方
  2. 调整布局样式,减小内容大小,让表格能显示完整,且多显示几行,使用 pagedjs

Q4

我发现一个大问题,就是我使用提一个文件,但是在其他新项目中写的demo 就能正确显示多页,而放在这个项目就只有一页。这说明应该是某一个 全局样式 影响了 vueprintnext 的样式行为,请你找到这个问题发生处

之前一页 Pasted image 20251128171612

现在 Pasted image 20251128171734

想法

我觉得可以直接生成一个统一的 打印并且包含固定部分(签名表)的 组件 和 composables 文件

应该是直接封装 composables 文件,里面需要几个功能:

  1. 获取重复内容(签名表)
  2. 获取选择内容的数据
  3. 根据选择的内容来生成 表格、html
  4. 使用 pagedjs 来优化样式
  5. 把最终获取到的完整内容加上 el 传入 vueprinternext 来渲染

直接在 原本打开预览界面的 按钮 替换为 vueprinternext 按钮,使用它自带的 preview dialog。

以函数式编程的方式来实现,也便于测试

创建于 2025/1/1 更新于 2026/5/27