项目背景
vue2.0项目,使用vue-print-nb插件实现打印功能
以下内容跟框架和插件关系不大,主要跟打印功能相关
踩坑记录:
1. 每页都需要页头页尾,比如页头是基本信息,页尾里是签名和备注提示,所以需要每页都有
table中thead和tfoot里的内容在打印分页时会自动带入每一页中,所以使用table排版,把页头放进thead中,页尾放入tfoot中,即可实现每页带入。
但是!像我们的项目各个模块的打印排版已经用div写好了,现在要改造,为了节约成本,我们在增加了一个全局的layout组件👇
html
<template>
<table>
<thead><tr><th>
<div>
<slot name="header" />
</div>
</th></tr></thead>
<tbody><tr><td>
<div>
<slot name="body" />
</div>
</td></tr></tbody>
<tfoot><tr><td>
<div>
<slot name="footer" />
</div>
</td></tr></tfoot>
</table>
</template>
然后在需要改造的打印模块中将表头内容表尾区分一下放入对应的slot中👇
html
<PrintLayout>
<template slot="header"></template>
<template slot="body"></template>
<template slot="footer"></template>
</PrintLayout>
2. 打印尺寸不统一,可能文件a固定要用A5,文件b有的部门用A4有的部门用A5
固定用某个尺寸可以直接设置@page{size: 'xxx'},所有打印统一的话直接全局设置最方便
css
/* Keyword values for scalable size */
size: auto;
size: portrait;
size: landscape;
/* <length> values */
/* 1 value: height = width */
size: 6in;
/* 2 values: width then height */
size: 4in 6in;
/* Keyword values for absolute size */
size: A4;
size: B5;
size: JIS-B4;
size: letter;
/* Mixing size and orientation */
size: A4 portrait;
我们项目是不统一的,所以如果是固定用某个小尺寸,会直接写死px值然后用margin: 0 auto;居中;不是固定尺寸的话需要自适应,字体样式排版需要多调试😮💨。
3. 页尾需要固定在每页的最下面 (这是最坑的地方😠)
最先尝试的是尺寸计算
的方式,这时候需要固定一个尺寸,比如1920像素下A4高度一页大概是1082px、A5高度一页大概是793px;
- 如果是用
table
写的,可以在dom渲染数据后获取每个tr的高度然后重组数据,即dataList刚开始是一个[],渲染出一个table,随后获取到所有的tr,循环去计算高度将dataList拆分成一个二维数据[[],[]], 然后每一项渲染出一个table,每个table加page-break-after:alawys;分页。这样的好处是算的比较精细,不容易出现高度误差的问题。示意图just like👇
- 如果是像我们用的是
layout
,排版都是一团一团通过slot塞进table里的,一个打印里还有有两三个dataList,就不太适用上面的方式,所以使用的是整体计算思维,在tbody下面填充将最后一页的tfoot撑到最下面,填充的高度就是需要计算的高度:每页固定尺寸减去thead高tfoot高就是每页中间tbody的高度a,每页tbody的高度 - tbody的高度 % 每页tbody的高度。示意图just like👇
存在问题:
- 需要固定一个尺寸,这个尺寸本身就是不准确的,像素不同纸张尺寸转化成的px数值就不同;
- margin值会被遗漏问题,tfoot下级的元素有margin值,获取tfoot的高度会不包含这个margin值的,thead、tbody同理,这时候页面就出现了未被计算的额外高度,会出现多一页纸的情况;
- 需要加载图片,图片load是需要时间的,会存在计算高度的时候图片还没loaded,就被忽略了,图片就是额外多出来的高度了
最后采用的方法是footer部分fixed排版
, 给tr元素fixed定位,tfoot给固定高度占位,这样页尾就会每页固定在最底部,又因为tfoot有高度占位了,不会和内容重叠显示;
css
// html
<tfoot>
<tr class="foot-fixed">
<td>
<div class="footer-content">
<slot name="footer" />
</div>
</td>
</tr>
</tfoot>
// js
const tfoot = document.querySelector('tfoot') || {} // 页脚
const footerContent = document.querySelector('footer-content')
let footHeight = footerContent.clientHeight
if (!footHeight) {
footHeight = 100
// 给个高度占位 这样body的内容就不会到下面来跟fixed的脚重叠
}
tfoot.style.height = `${footHeight}px`
// css
table {
min-height: 100vh;
}
.foot-fixed {
position: fixed;
bottom: 0;
z-index: -1;
width: 800px;
max-width: 100%;
}
存在问题:
- 不能生成两份文件同时预览打印,这时候会有两个fixed的foot,每页底部会有同时显示重叠的两个foot
- 需要加载图片,图片load是需要时间的,js计算高度给tfoot的时候,图片还没加载出来,就会被漏掉了,图片再加载出来显示就会和已有内容重叠在一起,可以给个包含图片的最小高度给图片显示先留位置,也可以等图片onload了再去加载打印dom
注意点记录
- 父级有元素设置transform样式,表格内元素设置fixed会不生效
- 页头跟纸张长度的比例有个临界值,超过了就不会每页都渲染页头,比如页头高度400,在A4就会每页渲染,A5就不行,临界值是多少? 我也不知道