簡單介紹一下前端打印的做法和一些問題
一、簡介
前端打印即瀏覽器打印,是通過瀏覽器的打印功能來實(shí)現(xiàn)打印效果的做法。
通過前端打印,可以實(shí)現(xiàn)的功能。

image.png
二、基本打印
首先用最普通的方式實(shí)現(xiàn)一些前端打印。
print.vue:
<template>
<div class="print-box" style="margin-left: 20px; margin-right: 20px">
<h2 class="print-header" style="margin-top: 0px">預(yù)分揀單</h2>
<div class="top-info-box">
<div class="flex-box">
<div class="flex-2">預(yù)分揀單:{{printData.crossDockingNo}}</div>
<div class="flex-1">總SKU數(shù):{{printData.skuQty}}</div>
<div class="flex-1">總PCS數(shù):{{printData.pcsQty}}</div>
</div>
<div class="flex-box">
<div class="flex-1">生單時(shí)間:{{printData.createTime}}</div>
<div class="flex-1">打印時(shí)間:{{printData.printTime}}</div>
</div>
</div>
<hr class="top-line" style="margin-top: 2px;margin-bottom: 2px;"/>
<ul class="printTable">
<li v-for="item in printData.commodityList" :key="item.commodityCode">
<div class="table-top-box">
<div class="flex-box">
<div class="flex-1">商品編碼:{{item.commodityCode}}</div>
<div class="flex-1">越庫數(shù)量:{{item.crossQty}}</div>
</div>
<div class="flex-box">
<div class="flex-2">品名:{{item.commodityName}}</div>
<div class="flex-1">規(guī)格:{{item.spec}}</div>
<div class="flex-1">單位:{{item.unit}}</div>
</div>
</div>
<table>
<thead>
<tr>
<th>門店編碼</th>
<th>門店名稱</th>
<th>門店庫位</th>
<th>播種數(shù)量</th>
</tr>
</thead>
<tbody>
<tr v-for="subItem in item.distributionDetail" :key="subItem.storeCode">
<td>{{ subItem.storeCode }}</td>
<td>{{ subItem.storeName }}</td>
<td>{{ subItem.collectionLocation}}</td>
<td>{{ subItem.matchQty }}</td>
</tr>
</tbody>
</table>
</li>
</ul>
<hr class="bottom-line" style="margin-top: 2px;margin-bottom: 2px;"/>
<div class="footer-center">
<el-button @click="startPrint" type="primary">打印</el-button>
</div>
</div>
</template>
<script>
export default {
data() {
return {
printData: {}
}
},
mounted() {
this.init();
},
methods: {
init() {
const data = {
'crossDockingNo': 'PSTSHW000218314-9999',
'skuCount': 3,
'pcsCount': 2452,
'createTime': '2018-03-14 17:40:01',
'printTime': '2018-03-14 17:40:01',
'commodityList': [
{
'commodityCode': 200004960001,
'commodityName': '薯片',
'spec': '32.4g',
'unit': '袋',
'crossQty': 150,
'distributionDetail': [
{
'storeCode': 0,
'storeName': '人廣店',
'collectionLocation': 'MENDIAN1',
'matchQty': 21,
}
]
}
],
};
for (let i = 0; i < 10; i++) {
const item = Object.assign({}, data.commodityList[0].distributionDetail[0]);
item.storeCode = i + 1;
data.commodityList[0].distributionDetail.push(item);
}
for (let i = 0; i < 10; i++) {
const item = Object.assign({}, data.commodityList[0]);
item.commodityCode = i + 1;
data.commodityList.push(data.commodityList[0]);
}
this.printData = data || {};
},
startPrint() {
// 打開一個(gè)新窗口
const myWindow = window.open('', '標(biāo)題');
// 獲取id為app內(nèi)的html
const bodyHtml = window.document.getElementById('app').innerHTML;
// 獲取head標(biāo)簽內(nèi)的html
let headHtml = document.head.innerHTML;
// 頭中的screen換成打印樣式print
headHtml = headHtml.replace('screen', 'screen, print');
//重新寫入文檔流
myWindow.document.write('<html>');
myWindow.document.write(headHtml);
myWindow.document.write('<body >');
myWindow.document.write(bodyHtml);
myWindow.document.write('<script>setTimeout(function() {window.print(); window.close();}, 500)</');
myWindow.document.write('script>');
myWindow.document.write('</body></html>');
}
}
};
</script>
<style lang="less" scoped>
@import url("./print.less");
</style>
print.less:
.print-box {
font-size: 12px;
padding: 2px;
@media print {
font-family: "PingFang SC", "Hiragino Sans GB", "Helvetica Neue", Roboto, Noto, sans-serif;
}
.print-header {
text-align: center;
margin-top: 15px;
font-weight: bold;
}
.top-line {
height: 10px;
border: none;
border-top: 10px groove;
margin-top: 12px;
margin-bottom: 12px;
}
.table-top-box {
font-size: 18px;
}
.flex-box {
display: flex;
.flex-2 {
flex: 2;
}
.flex-1 {
flex: 1;
}
}
.printTable li {
margin-top: 20px;
.table-top-box {
margin-bottom: 10px;
}
}
.bottom-line {
height: 1px;
border: none;
border-top: 3px groove; /* solid */
margin-top: 12px;
margin-bottom: 12px;
}
@border-color: #e1e1e1;
.printTable {
table {
text-align: center;
font-size: 12px;
border: 1px solid @border-color;
width: 100%;
th, td {
padding: 1px;
border-bottom: 1px solid @border-color;
border-right: 1px solid @border-color;
}
th {
text-align: center;
&:last-child {
border-right: none;
}
}
tr {
td:last-child {
border-right: none;
}
&:last-child {
td {
border-bottom: none;
}
}
}
}
}
.footer-center {
@media print {
display: none;
}
margin-top: 12px;
text-align: center;
}
}
打印預(yù)覽:
image.png
三、功能設(shè)置
3.1 頁面設(shè)置
@page 規(guī)則用于指定打印頁面的一些屬性,包括紙張尺寸、方向、頁邊距、分頁等特性。
@page :pseudo-class {
size: A4 landscape;
margin:2cm;
}
3.2 分頁
page-break-before用于設(shè)置元素前面的分頁行為,可取值:
- auto默認(rèn)值。如果必要?jiǎng)t在元素前插入分頁符。
- always在元素前插入分頁符。
- avoid避免在元素前插入分頁符。
- left在元素之前足夠的分頁符,一直到一張空白的左頁為止。
- right在元素之前足夠的分頁符,一直到一張空白的右頁為止。
- inherit規(guī)定應(yīng)該從父元素繼承 page-break-before 屬性的設(shè)置。
page-break-after設(shè)置元素后的分頁行為。取值與page-break-before一樣。
page-break-inside設(shè)置元素內(nèi)部的分頁行為。取值如下:
- auto默認(rèn)。如果必要?jiǎng)t在元素內(nèi)部插入分頁符。
- avoid避免在元素內(nèi)部插入分頁符。
- inherit規(guī)定應(yīng)該從父元素繼承 page-break-inside 屬性的設(shè)置。
@media print {
section {page-break-before: always;}
h1 {page-break-after: always;}
p {page-break-inside: avoid;}
}
3.3 分頁保留行數(shù)
orphans設(shè)置當(dāng)元素內(nèi)部發(fā)生分頁時(shí)必須在頁面底部保留的最少行數(shù)。
widows設(shè)置當(dāng)元素內(nèi)部發(fā)生分頁時(shí)必須在頁面頂部保留的最少行數(shù)。
@media print {
p {orphans:3; widows:2;}
}
3.4 顯示背景色
打印默認(rèn)不顯示背景色,在 screen 下的設(shè)置是不起效果的。
可以通過設(shè)置改變。
@media print {
* {
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
}
四、其他
- 對(duì)于頁面上有顯示而不想打印的內(nèi)容,可以將其display設(shè)置為none來避免打印。
- 需要打印的內(nèi)容盡量避免float,有些瀏覽器不會(huì)正確的打印浮動(dòng)的內(nèi)容。
- 可以調(diào)用window.print()函數(shù)來打印當(dāng)前頁面。
- 分頁打印或換頁打?。?strong>page- break-before 和 page-break-after CSS屬性并不會(huì)修改網(wǎng)頁在屏幕上的顯示,這兩個(gè)屬性是用來控制文件的打印方式。
