由于开发框架使用jsp,所以本文以jsp做示例,其他框架遵循框架语法即可,底层都是通过调用浏览器组件打印html
思路:
需要触发打印的页面添加打印按钮(当然这是废话,从这里开个头吧),和一个iframe
<iframe id="print-cover-iframe" frameborder="0" style="display: none;"></iframe>
点击按钮时,动态设定当前iframe的src,使得iframe加载并渲染需要打印的html(所以本文讲的是动态获取html并打印,而非打印当前页面已有的一段html)
$("#btn_print").unbind("click").click(function() {
console.log('点击打印');
var url = '项目中需要打印的页面(我这里是前后端不分离的jsp,所以是后端的url会自动跳转到jsp页面),如果是前后端分离的,可以直接是html的页面路由';
var iframeId = 'print-cover-iframe';
var $iframe = $('#' + iframeId);
$iframe.attr('src', url);
$iframe.load(function() {
var HTML = document.getElementById(iframeId);
HTML.focus();
HTML.contentWindow.print();
});
});
最后一步,也是最重要的一步:编写需要打印的页面,调起打印的页面样式设定还是有很多坑的,这里直接晒出jsp的页面(注:本文jsp页面是跳转前携带参数,接口分装参数并在jsp页面动态渲染的,前后端分离的项目,这个页面中可以在页面加载方法中触发动态绑定数据)
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
<c:set var="ctx" value="${pageContext.request.contextPath}"/>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<script src="${pageContext.request.contextPath}/back/angularJs/jquery-2.1.3.min.js" type="text/javascript"></script>
<script src="${pageContext.request.contextPath}/back/angularJs/jquery.qrcode.min.js" type="text/javascript"></script>
<head>
<meta charset="UTF-8">
<title>批量打印</title>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
<style type="text/css">
.qrcode{
<%--background: url('${ctx}/back/image/img_chaobiao.png') no-repeat center center;--%>
/*background-size:100% 100%;*/
width: 92mm;
height: 92mm;
/*margin: 2mm;*/
margin-left: 4mm;
z-index: 8;
position: relative;
/*margin-top: 5mm;*/
/*-webkit-print-color-adjust: exact;*/
}
.qrcode > img {
object-fit: contain;
width: 100%;
height: 100%;
position: absolute;
}
.qrcode-img{
z-index: 10;
top: 22mm;
left: 23mm;
/*height: 60mm;*/
/*width: 55mm;*/
position: absolute;
}
.qrcode-img > canvas{
width: 42mm;
height: 42mm;
}
.qrcode > img {
object-fit: contain;
width: 100%;
height: 100%;
}
.background-img{
/*position: absolute;*/
z-index: 5;
}
.title-dev{
/*width: 601px;*/
/*height: 108px;*/
overflow-wrap: break-word;
color: white !important;
font-family: PingFangSC-Medium;
text-align: center;
line-height: 10mm;
margin-left: 27mm;
margin-top: 20mm;
z-index: 10;
width: 40mm;
position: absolute;
}
@media print {
.collage_bg {
background-color: #E6E7E9 !important;
-webkit-print-color-adjust: exact;
}
}
@media print {
.print-padding {
position: absolute;
padding: 12% 8% 0 3.1%;
z-index: 10;
}
.page-break{
page-break-after:always;
}
.title-dev{
color: #FFFFFFFF !important;
}
body {
/*此样式可防止打印的字体、背景色与设定的不一样问题*/
-webkit-print-color-adjust: exact;
}
}
@page {
margin-top: 0;
margin-bottom: 0;
size: portrait;/*(纵向)*/
}
#print_box {
/*position: static;*/
}
.qrcode > img {
/*position: absolute;*/
z-index: 5;
object-fit: contain;
/*margin: 15px -40px;*/
}
.table {
margin-bottom: 5px;
}
.box{
display: flex;
flex-wrap: wrap;
}
.item{
align-self: auto;
}
</style>
</head>
<body>
<%-- 定义一个长度为6的数组,每6个二维码分一页 --%>
<%
String[] str={"1","2","3","4","5","6"};
request.setAttribute("str",str);
%>
<%-- 循环渲染二维码,每6个二维码分一页 ps:使用嵌套循环而不用判断当前index取模的方式是因为Edge等浏览器分页符需要在最外层标签才生效--%>
<c:forEach var="item" items="${qrCodes}" step="6" varStatus="status">
<div class="box">
<c:forEach items="${str}" var="s" varStatus="intStatus">
<c:if test="${(status.index + intStatus.index) < fn:length(qrCodes)}">
<div class="item">
<div class="qrcode">
<img src="${ctx}/back/image/img_chaobiao.png" class="visible-print-block background-img"/>
<div class="qrcode-img print-padding" id="qrcode_${qrCodes[status.index + intStatus.index].id}"></div>
<div class="title-dev">${qrCodes[status.index + intStatus.index].qrCodeName}</div>
</div>
</div>
</c:if>
</c:forEach>
</div>
<c:if test="${!status.last}">
<div class="page-break"></div>
</c:if>
</c:forEach>
<%--<div class="box">
<c:forEach items="${qrCodes}" var="qrCode" varStatus="status">
<div class="item">
<div class="qrcode">
<img src="${ctx}/back/image/img_chaobiao.png" class="visible-print-block background-img"/>
<div class="qrcode-img print-padding" id="qrcode_${qrCode.id}"></div>
<div class="title-dev">${qrCode.qrCodeName}</div>
</div>
</div>
<c:if test="${status.count%6==0 && !status.last}">
<div class="page-break"></div>
</c:if>
</c:forEach>
</div>--%>
<script type="text/javascript">
<c:forEach var="item" items="${qrCodes}" varStatus="status">
qrcode('qrcode_${item.id}','${item.id}');
</c:forEach>
function qrcode(id,content){
$("#" + id).qrcode({
width: 120, //宽度
height: 120, //高度
text: utf16to8(content), //内容
typeNumber: -1,//计算模式
correctLevel: 1,//二维码纠错级别
background: "#ffffff",//背景颜色
foreground: "#000000" //二维码颜色
});
}
//中文编码格式转换
function utf16to8(str) {
var out, i, len, c;
out = "";
len = str.length;
for (i = 0; i < len; i++) {
c = str.charCodeAt(i);
if ((c >= 0x0001) && (c <= 0x007F)) {
out += str.charAt(i);
} else if (c > 0x07FF) {
out += String.fromCharCode(0xE0 | ((c >> 12) & 0x0F));
out += String.fromCharCode(0x80 | ((c >> 6) & 0x3F));
out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
} else {
out += String.fromCharCode(0xC0 | ((c >> 6) & 0x1F));
out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
}
}
return out;
}
</script>
</body>
</html>
最后,晒出效果(灰色块为马赛克):
