1.1 前言
本文包含浏览器原生打印的常用技术点:打印样式纸张修改、分页相关、唤起别的页面打印、局部打印等。
如果文章帮到你了,可以点个赞。
1.2 修改打印样式
使用@media print或<link href="" media="print" rel="stylesheet" />
注意:不是所有样式都能应用在打印中,具体在打印预览窗口查看是否生效。
/* 其内部样式只在打印时生效 */
@media print {
/* 隐藏非打印元素 */
... {
display: none !important;
}
/* 隐藏不必要的边距 */
... {
margin: 0 !important;
padding: 0 !important;
}
/* 重置所有样式 */
... {
all: unset !important;
}
}
1.3 修改打印纸张和方向
使用@page的size属性,可以使用不同的打印纸张、切换打印方向,以及自定义纸张大小。
注意:实际打印纸张以打印窗口中选择的为准。
@media print {
@page {
size: A4 landscape; // 使用A4纸张,横向打印
// size: 50mm 150mm; // 自定义纸张大小
}
}
1.4 修改页边距(去除浏览器自带的页眉页脚)
使用@page的margin属性,可以修改页边距,去除浏览器自带的页眉页脚。
注意:浏览器的自带的页眉页脚是不能修改的,要想自定义就得先去除它,再自己实现。
@media print {
@page {
margin: 15mm; // A4纸页边距
// margin: 0; // 去除浏览器自带的页眉页脚
}
}
自己实现页眉页脚的思路:
将页面分成三个部分:重复的页眉、重复的页脚、内容,然后根据数据动态生成页面,生成时要检查内容高度是否超过阈值(即内容高度 = 页面高度 – 页眉高度 – 页脚高度),如果超过了,就裁剪数据再生成新页面。
1.5 强制分页
page-break-before: always; // 强制在元素前分页
page-break-after: always; // 强制在元素后分页
1.6 自动分页
要打印的内容区域,有滚动条,怎么打印完整?
怎么在唤出打印预览窗口时,浏览器自动分页,而不是只打印可视区?
关键在于,只让body滚动,这就够了。
@media print {
.common-layout,
.main-body,
.gmp-container {
/* 打印区域及其所有父级元素只要有设置过overflow,全部重置 */
overflow: unset !important;
}
body {
/* 只有body设为auto */
overflow: auto !important;
}
}
1.7 表格分页时表头重复
当上面表格长过一页时,浏览器会在下一页的顶部自动复制<thead>。
<table>
<thead> // 关键
<tr>
<th>列1</th>
<th>列2</th>
</tr>
</thead>
<tbody>
<tr><td>0</td><td>0</td></tr>
<tr><td>1</td><td>1</td></tr>
<tr><td>2</td><td>4</td></tr>
...
</tbody>
</table>
1.8 在当前页面打印别的页面
function handleGmpPrint() {
const hideMessage = message.loading('正在准备打印...', 0)
const hideFrame = document.createElement('iframe')
hideFrame.addEventListener('load', () => {
hideMessage()
hideFrame.contentWindow?.addEventListener('afterprint', () => {
document.body.removeChild(hideFrame)
})
hideFrame.contentWindow?.print()
})
hideFrame.style.display = 'none'
hideFrame.src = '/gmp/print' // 指定要打印的页面路由
document.body.appendChild(hideFrame)
}
打印数据可以【通过url带参在打印页请求】或【直接通过状态管理库、localStorage传递】,
期间可能存在异步问题,利用定时器监听某个指标,这个指标只在打印数据加载完成时为true.
1.9 局部打印
局部打印:只打印部分内容,而不是整个页面打印
1. 把内容放入新页面中打印或修改原页面body(不推荐,用户体验不好)
2. 把内容放入隐藏的iframe中打印(不推荐,比较麻烦,样式不好处理,表单输入会丢失)
3. 隐藏所有不需要打印的元素(推荐)
方法三:通过动态控制no-print类,再配合nextTick实现局部打印
@media print {
.no-print {
display: none !important;
}
}
<div class="print-page" :class="{ 'no-print': currentItemIndex !== 1 }">
/** 当前要局部打印的项索引 */
const currentItemIndex = ref(0)
/** 局部打印 */
function handleItemPrint(index: number) {
currentItemIndex.value = index
nextTick(() => {
window.print()
})
}
最后
之前使用vue-plugin-hiprint也实现过打印功能,包含自动打印、选择打印机、自定义打印模板设计等,有兴趣的朋友可以看看,文章地址。