相信大家平时做项目时,打印需求很常见,但想把打印做好,还是要花点时间的。特别是长列表要分页的情况。
我们知道浏览原生 API ```window.print()``` 可以用于印当前窗口(window.document)视图内容。调用此方法会产生一个打印预览弹框,用户可以根据具体设置来得到打印结果。
一、window的打印事件
默认情况下,调用 window.print() 会对整个 document.body 进行打印,当需要打印指定容器内容时,可以这样做:
1、先获取指定容器中的内容,将body的内容替换掉,调用了打印方法后,再把原来的body恢复。
html
<body>
<div id="container1">
<p>这是第一个段落</p>
</div>
<div id="container2">
<p>这是第二个段落</p>
</div>
<input type="button" value="打印此页面" onclick="printPage()" />
<script>
const printPage= () => {
let newstr = document.getElementById("container1").innerHTML;
let oldstr = document.body.innerHTML;
document.body.innerHTML = newstr;
window.print();
document.body.innerHTML = oldstr;
</script>
</body>
2、监听打印前、后事件实现区域打印
window.onbeforeprint()、window.onafterprint()
html
<body>
<div id="container">
<p>这是一个段落</p>
<h1 id="title">这是一个标题</h1>
</div>
<input type="button" value="打印此页面" onclick="printPage()" />
<script>
const printPage= () => {
window.print();
}
// 打印前事件
window.onbeforeprint = function() {
// 隐藏不需要打印的元素
document.getElementById('title').style.display = 'none';
}
// 打印完成后
window.onafterprint = function() {
// 放开隐藏的元素
document.getElementById('title').style.display = 'block';
}
</script>
</body>
二、打印样式
我们页面的样式和打印页面时的样式是两个不同的样式,打印时会默认携带页面的样式,同时呢我们也可以修改页面打印时的样式。修改打印样式的方法:
1、使用内联media属性
html
<style media="print">
.container{
width:800px;
}
</style>
2、使用媒体查询
html
<style>
@media print {
h1{
color: #333;
background: #ccc;
}
}
</style>
3、引入打印样式表
例如:print.css
css
@media print {
@page {
size: auto;
margin: 20px 30px;
}
#mainBody{
margin-top:0 !important;
margin-bottom:0 !important;
}
}
用link引入
html
<link rel="stylesheet" type="text/css" href="./css/print.css" media="print" />
注意:
1、如果是前后不分离的项目,在样式中用到`@`时可能会报错:"上下文中未定义@media或@page",这时候我们可以用`<link>`的方式引入。
2、修改打印样式时必须确保打印机样式实际上确实覆盖了主样式表。可以使用!important。
3、@page属性可以控制打印页面的边距大小和页眉页脚
css@media print { @page { size: auto; // {size:A4}、{size: 800px 1200px}、{size:portrait}竖向打印、{size:landscape}横向打印 margin: 20px 30px; // 边距,可去除页眉页脚 } // 覆盖页面原有样式 #container{ margin-top:0 !important; margin-bottom:0 !important; } }
4、-webkit-print-color-adjust:是一个在浏览器中强制打印背景颜色和字体颜色的css属性,当打印出来的某些元素的背景颜色没有被显示时,可以使用
-webkit-print-color-adjust:exact
5、
当需要自定义打印分页时机时,可通过如下方式将指定 DOM 设为分割点。
css@media print { h1 { page-break-before: always; //在指定元素前面添加分页符 } #title { page-break-after: always;//在指定元素后面添加分页符 } }
三、长列表打印
打印长列表时会要求自动分页,但添加了分页符效果可能并不理想。最常见的就是表格行被从中间截断,那要怎么解决呢?
其实我们只要控制打印的行数就可以了。我们需要知道打印元素的高度和表格行的高度,算出一页纸可以打印多少行,超出的部分放到下一页打印。(一页放多少行没必要计算,根据打印元素的高度估算下就可以了。)
示例:
html
<style>
body {
font-family: "微软雅黑",Verdana,SimHei,"Microsoft JhengHei",Tahoma;
line-height: 1.5;
background-color: #ffffff;
margin: 0;
}
// 打印容器
#mainBody {
margin: 20px 20px 0 20px;
}
table {
border: 1px solid #000;
border-collapse: collapse;
width: 100%;
}
table td {
border: 1px solid #000;
height: 30px;
text-align: center;
}
table th {
border: 1px solid #000;
height: 30px;
text-align: center;
}
.printContainer {
margin: 0 auto;
// 打印内容宽高
width: 1052px;
height: 1480px;
position: relative;
}
.printTitle {
font-size: 22px;
font-weight: bold;
text-align: center;
}
.printnav {
display: flex;
justify-content: space-between;
}
.signature_footer {
position: absolute;
width: 100%;
bottom: -20px;
display: flex;
justify-content: space-around;
font-size: 20px;
}
</style>
<body>
<div id="mainBody"></div>
</body>
<script>
$(document).ready(function () {
getList()
})
//获取地址栏参数
function getUrlParam(name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); //构造一个含有目标参数的正则表达式对象
var r = window.location.search.substr(1).match(reg); //匹配目标参数
if (r != null) return unescape(r[2]); return null; //返回参数值
}
// 将列表数据分页,array要分页的数据,subNum是每页多少条(根据纸张大小估算一页能展示多少条)
function groupArray(array, subNum) {
let index = 0
let newArray = []
while (index < array.length) {
newArray.push(array.slice(index, (index += subNum)))
}
return newArray
}
// 获取数据源,页面添加元素
function getList() {
var params = {
PatientID: getUrlParam('PatientID'),
BedNo: getUrlParam('BedNo'),
xdStartDate: getUrlParam('StartDate'),
xdEndDate: getUrlParam('EndDate')
}
$.get('/IndexPrintList', params, function (res) {
// 先清空上一次的数据
$('#mainBody').empty()
// 分页的数据,返回的数组长度即页数
var arr = groupArray(res.alist, 14)
if (arr.length) {
for (let i = 0; i < arr.length; i++) {
// 创建打印元素
$('#mainBody').append(`<div class="printContainer">
<div class="printTitle">${res.hospitalName}</div>
<div style="text-align:center;font-weight:bold;font-size:20px;margin:20px 0;">定点血糖记录表</div>
<div class="printnav" style="margin: 10px 0; font-size:14px;">
<div>
患者ID: ${res.patientModel.no}
</div>
<div>
姓名:${res.patientModel.name}
</div>
<div>
性别: ${res.patientModel.sex == 0 ? "男" : "女"}
</div>
<div>
病区:${res.patientModel.Bed.WardModel.wardName}
</div>
<div>
床号:${res.patientModel.Bed.innerOrder}
</div>
<div>
测量次数:${res.allNum}
</div>
</div>
<div class="printContent">
<table>
<thead>
<tr>
<th colspan="2">日期\监测点</th>
${res.SortList.map(column => {
return `
<th>${column.name}</th>
`
}).join("")}
</tr>
</thead>
<tbody>
${arr[i].map(row => {
return `
<tr>
<td rowspan="3" style="width:90px">${row.measureTime}</td>
<td>血糖值(mmol/L)</td>
${res.MeasurePointList.map(point => {
if (row.dict[point.id]) {
return `
<td style="color:${row.dict[point.id].color}"> ${row.dict[point.id].Value}
</td>`
} else {
return `<td></td>`
}
}).join("")}
</tr>
<tr>
<td>操作者</td>
${res.MeasurePointList.map(point => {
if (row.dict[point.id]) {
return `<td>${row.dict[point.id].AccountName}</td>`
} else {
return `<td></td>`
}
}).join("")}
</tr>
<tr>
<td>测量时间</td>
${res.MeasurePointList.map(point => {
if (row.dict[point.id]) {
return `<td>08:00</td>`
} else {
return `<td></td>`
}
}).join("")}
</tr>
`
}).join("")
}
</tbody>
</table>
</div>
<div class="signature_footer">
<div>医生手签:</div>
<div style="margin-right:30px;">质控护士手签:</div>
</div>
</div>`)
}
}
window.print();
})
}
</script>
代码解释:
1、首先给打印元素设置宽和高,高度根据需要或实际情况设置。(可根据A4纸大小来定)
2、通过接口拿到长列表数据,然后用`groupArray`方法计算需要打印几页。(groupArray函数返回一个二维数据,二维数组的长度就是页数,二维数组的每一项就是每页的数据)
3、根据这个二维数组循环创建要打印的元素。(类`.printContainer`是要打印的整体内容,即一页纸的内容,arr[i]就是每页的表格数据)
4、示例中每页都加了标题和签名,表格有合并单元格。
5、简单表格如下:
html
<table>
<thead>
<tr>
<th>检测日期</th>
<th>检测值</th>
<th>操作护士</th>
</tr>
</thead>
<tbody>
${arr[i].map(item=>{
return `<tr>
<td>${item.MeasureDateStr}</td>
<td>${item.value}</td>
<td>${item.AccountName}</td>
</tr>`
}).join("")
}
</tbody>
</table>