前言
前端实现打印方案有很多,但是有一些缺点与不足
主要缺点
-
没有预览功能
-
打印不清晰
-
分页切分显示不全
-
...
并且,信息填写类实现打印功能,一般要有 [预览] 和 [打印] 两个功能
很多插件都不支持 [预览] 功能,而且如果你只是实现简单的 [预览] 和 [打印],完全没必要折腾其他插件
实现
window.print
首先我们创建一个 index.html,修改下基本样式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
.list-card {
width: 900px;
background: #ffffff;
border-radius: 10px;
margin: 20px 0;
padding: 20px;
}
.table-layout {
width: 100%;
table-layout: fixed;
border-collapse: collapse;
}
.table-cell {
display: table-cell;
text-align: center;
height: 60px;
border: 1px solid #e4e4e4;
color: #333333;
font-size: 14px;
}
</style>
</head>
<body>
<button onclick="print()">打印</button>
<div class="list-card">
<div class="table-container">
<div class="table-container">
<table class="table-layout">
<tbody>
<tr>
<td class="table-cell">
左青龙
</td>
<td class="table-cell" colspan="6">
右白虎
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</body>
</html>
效果有了,现在我们需要去做点击下打印按钮,就会调起浏览器打印
我们写个函数来实现
const print = () => {
const newDom = document.querySelector(".list-card").innerHTML;
const oldDom = document.body.innerHTML;
document.body.innerHTML = newDom;
window.print();
document.body.innerHTML = oldDom;
}
可以出现来效果了
但是,会有两个问题
- 打印的表格右边显示不全
- 我们再点击打印按钮,无效了
先解决下,打印不全的问题,我们可以通过 @Page 来设置打印的样式
@page {
margin: 20px 20px 0;
}
可以了,那这个打印按钮无效的问题呢?
那是因为,我们调用 window.print() 后,整个页面都被锁住了
我们需要通过 window.location.reload() 重新加载页面
但是这样就会,导致页面重新刷新,那么如果是需要填写的表单,可能数据就没了
为了解决这问题,我们可以使用 iframe 来实现
const print = () => {
// 获取打印的元素
const dom = document.querySelector(".list-card").outerHTML;
// 创建 iframe,设置 absolute、width、height 让元素隐藏再浏览器窗口外,并将 iframe 加入到 body 中
const iframe = document.createElement("iframe");
iframe.setAttribute("style", "position:absolute;width:0;height:0;top:-10px;left:-10px;");
document.body.appendChild(iframe);
const iframeDom = iframe.contentDocument;
let str = ''
const styles = document.querySelectorAll("style,link").forEach(item => {
str += item.outerHTML;
});
// 将打印元素与样式加入 iframe
iframeDom.open();
iframeDom.write(str + dom);
iframeDom.close();
iframe.contentWindow.print();
// 打印关闭后,移除 iframe 元素
document.body.removeChild(iframe);
}
实现逻辑就是,将要打印的内容放到 iframe ,打印完成后移除 iframe
完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
/*
body {
background: #000000;
} */
.list-card {
width: 900px;
background: #ffffff;
border-radius: 10px;
margin: 20px 0;
padding: 20px;
}
.table-layout {
width: 100%;
table-layout: fixed;
border-collapse: collapse;
}
.table-cell {
display: table-cell;
text-align: center;
height: 60px;
border: 1px solid #e4e4e4;
color: #333333;
font-size: 14px;
}
@page {
/* size: auto; */
margin: 20px 20px 0;
}
</style>
</head>
<body>
<button onclick="print()">打印</button>
<div class="list-card">
<div class="table-container">
<div class="table-container">
<table class="table-layout">
<tbody>
<tr>
<td class="table-cell">
左青龙
</td>
<td class="table-cell" colspan="6">
右白虎
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</body>
</html>
<script>
// const print = () => {
// const newDom = document.querySelector(".list-card").innerHTML;
// const oldDom = document.body.innerHTML;
// document.body.innerHTML = newDom;
// window.print();
// document.body.innerHTML = oldDom;
// window.location.reload();
// }
const print = () => {
const dom = document.querySelector(".list-card").outerHTML;
const iframe = document.createElement("iframe");
iframe.setAttribute("style", "position:absolute;width:0;height:0;top:-10px;left:-10px;");
document.body.appendChild(iframe);
const iframeDom = iframe.contentDocument;
let str = ''
const styles = document.querySelectorAll("style,link").forEach(item => {
str += item.outerHTML;
});
iframeDom.open();
iframeDom.write(str + dom);
iframeDom.close();
iframe.contentWindow.print();
document.body.removeChild(iframe);
}
</script>
小结
window.print 直接实现打印,会出现引起页面刷新,从而容易导致页面已有表单信息缺失
为了解决这个问题,我们将打印数据放入 iframe ,再调用浏览器打印,完成后再删除 iframe
其中需要注意的是,iframe 得让其远离浏览器视图,这样才能保证不会影响到原来的视图