之前写过一篇文章CSS实现自动分页打印同时每页保留重复的自定义内容,可以实现window.print()
打印时多张页面保留相同的内容(如header、footer),但其并不是真正意义上的页眉页脚,footer内容在最后一张页面未撑满时不能置于页面底部。为了实现打印使用CSS自定义页眉页脚,解决之前遗留的问题,本文对之前的办法做了改进,提出了一种解决方案。
效果图
基本原理
- 在要打印的内容中,页眉页脚元素使用
position: fixed
,并设定各自的高度。 - 正文内容使用
table
元素,table
的开头(thead
)和结尾(tfoot
)各使用一个设定高度(大于等于页眉页脚高度)的空DOM元素,防止页眉页脚与正文内容重叠。
此时即可实现自定义页眉页脚,调用window.print()
时多张页面具有相同的页眉页脚,且页眉页脚可自定义内容,包括插入logo等图片。
示例代码
只打印指定dom内容,要打印的内容在#printDom
中,页面在非打印模式不会显示其内容,只有在点击打印按钮调用window.print()
时才会显示打印内容。
下方两个示例代码一样,根据个人阅读方式喜好查看。
示例代码-github:github
示例代码:
<html>
<head>
<title>print demo</title>
<meta name="description" content="CSS打印,支持自定义页眉页脚" />
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
<meta
name="viewport"
id="WebViewport"
content="initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
/>
<style>
@media print {
@page {
size: A4 portrait;
/* 调整页边距 */
margin: 1cm 1cm 1cm;
}
#printDom {
display: block !important;
}
}
#printDom {
/* 打印区域在非打印时不显示 */
display: none;
position: relative;
font-size: 16px;
font-family: SimSun, Songti SC;
}
#printDom .page-header {
/* 页眉高度 */
height: 2cm;
display: flex;
align-items: center;
position: fixed;
top: 0mm;
width: 100%;
border-bottom: 1px solid #ddd;
z-index: 2000;
}
#printDom .page-header-space {
/* 控制内容区距离顶部的距离,防止与页眉重叠 */
height: 2cm;
}
#printDom .page-footer {
/* 页脚高度 */
height: 1cm;
position: fixed;
bottom: 0;
width: 100%;
border-top: 1px solid grey;
z-index: 2000;
}
#printDom .page-footer-space {
/* 控制内容区距离底部的距离,防止与页脚重叠 */
height: 1.5cm;
}
#printDom > table {
width: 100%;
}
#printDom .content table {
width: 100%;
font-size: 30px;
}
#printDom .content .header {
text-align: center;
}
</style>
</head>
<body>
<button onclick="handlePrint()">打 印</button>
<div id="printDom">
<!-- 页眉 -->
<div class="page-header">Logo</div>
<table>
<!-- 占位,给页眉留出位置 -->
<thead>
<tr>
<td><div class="page-header-space"></div></td>
</tr>
</thead>
<!-- start: 正文 -->
<tbody>
<tr>
<td>
<div class="content">
<!-- 正文的标题 -->
<h1 class="header">H1</h1>
<div>
<!-- 正文内容,可随意写,demo是表格 -->
<table>
<thead>
<tr>
<td>Index</td>
<td>Name</td>
</tr>
</thead>
<tbody id="tableBody">
</tbody>
<tfoot></tfoot>
</table>
</div>
</div>
</td>
</tr>
</tbody>
<!-- end: 正文 -->
<!-- 占位,给页脚留出位置 -->
<tfoot>
<tr>
<td><div class="page-footer-space"></div></td>
</tr>
</tfoot>
</table>
<!-- 页脚 -->
<div class="page-footer">Footer</div>
</div>
<script>
/**
* 打印指定元素
* @param {string} element 需要打印的元素选择器
*/
function printElement(element) {
var printContents = document.querySelector(element).cloneNode(true);
var popupWin = window.open('', '_blank');
popupWin.document.open();
const styles = document.head.innerHTML;
popupWin.document.write(`<html><head><title>Print Title</title>${styles}</head><body οnlοad="window.print(); window.close();">`);
popupWin.document.body.appendChild(printContents);
popupWin.document.write('</body></html>');
popupWin.document.close();
}
function handlePrint() {
printElement('#printDom');
}
const tempTableData = document.querySelector('#tableBody');
const tempFragument = document.createDocumentFragment();
// mock data
for (let i = 0; i < 30; i++) {
const _tr = document.createElement('tr');
const _td1 = document.createElement('td');
_td1.appendChild(document.createTextNode(`No${i + 1}`));
const _td2 = document.createElement('td');
_td2.appendChild(document.createTextNode(new Date().getTime()));
_tr.appendChild(_td1);
_tr.appendChild(_td2);
tempFragument.appendChild(_tr);
}
tempTableData.appendChild(tempFragument);
</script>
</body>
</html>