vue中实现打印功能的几种方法
·
1、直接调用 window.print()方法
这种方法默认打印整个页面,不能打印局部页面。并且不保留原有样式
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>打印测试页</title>
<style type="text/css"
media="screen">
.pageheader,
.pagefooter {
display: none;
}
</style>
<style type="text/css"
media="print">
/*每一页 如果没有另外自定义的话 */
@page {
margin-left: 50px;
margin-top: 100px;
}
/*第一页*/
@page :first {
margin-left: 50%;
margin-top: 50%;
}
/*分页标记*/
.geovindu {
page-break-after: always;
}
.pageheader {
margin-top: 10px;
font-size: 12pt;
}
.pagefooter {
margin-top: 10px;
font-size: 10pt;
}
</style>
</head>
<body>
<script type="text/javascript">
function main() {
window.print();
}
</script>
<div id="geovindu"
class="geovindu">
<div class="pageheader">页眉:打印测试</div>
<div class="conent">
封面内容
</div>
<div class="pagefooter">页脚:第1页/共2页</div>
</div>
<div id="geovindu"
class="geovindu">
<div class="pageheader">页眉:打印测试</div>
<div class="conent">
第二页内容
</div>
<div class="pagefooter">页脚:第2页/共2页</div>
</div>
<button onclick="main()">打印按钮</button>
</body>
</html>
2、自定义封装打印方法
这种方法也是调用了原生打印,通过封装好方法,可以指定需要打印的区域,自由度高,缺点就是通过截取全页面的html进行字符串截取,并且不保留原有样式,需要去手动添加样式。
2.1、封装打印方法,创建一个printHtml.js文件
export default function printHtml(html) {
let style = getStyle();
let container = getContainer(html);
document.body.appendChild(style);
document.body.appendChild(container);
getLoadPromise(container).then(() => {
window.print();
document.body.removeChild(style);
document.body.removeChild(container);
});
}
// 设置打印样式
function getStyle() {
let styleContent = `#print-container {
display: none;
}
@media print {
body > :not(.print-container) {
display: none;
}
html,
body {
display: block !important;
}
#print-container {
display: block;
}
}`;
let style = document.createElement("style");
style.innerHTML = styleContent;
return style;
}
// 清空打印内容
function cleanPrint() {
let div = document.getElementById('print-container')
if (!!div) {
document.querySelector('body').removeChild(div)
}
}
// 新建DOM,将需要打印的内容填充到DOM
function getContainer(html) {
cleanPrint()
let container = document.createElement("div");
container.setAttribute("id", "print-container");
container.innerHTML = html;
return container;
}
// 图片完全加载后再调用打印方法
function getLoadPromise(dom) {
let imgs = dom.querySelectorAll("img");
imgs = [].slice.call(imgs);
if (imgs.length === 0) {
return Promise.resolve();
}
let finishedCount = 0;
return new Promise(resolve => {
function check() {
finishedCount++;
if (finishedCount === imgs.length) {
resolve();
}
}
imgs.forEach(img => {
img.addEventListener("load", check);
img.addEventListener("error", check);
})
});
}
2.2、使用方式
<template>
<div>
<button @click="onPrint">打印1</button>
// dom部分 可用if控制
<i test='printStart'></i>
<div v-show="oldStr">
v-show1的
</div>
<div v-show="oldStr">
v-show2的
</div>
测试冲冲冲
<div class="xwtable">
<table>
<tr>
<th>序号</th>
<th>姓名</th>
<th>年龄</th>
<th>性别</th>
<th>手机</th>
<th>邮箱</th>
<th>地址</th>
<th>工龄</th>
<th>岗位</th>
<th>薪资</th>
</tr>
<tr v-for="(item, index) in list"
key="index">
<td>{{ index + 1}}</td>
<td>{{ item.name }}</td>
<td>{{ item.age }}</td>
<td>{{ item.sex }}</td>
<td>{{ item.phone }}</td>
<td>{{ item.mail }}</td>
<td>{{ item.address }}</td>
<td>{{ item.workAge }}</td>
<td>{{ item.jobs }}</td>
<td>{{ item.salary }}</td>
</tr>
</table>
</div>
<i test='printEnt'></i>
<div>
<div class="text_styte">我是测试样式的</div>
</div>
</div>
</template>
<script setup lang="ts">
// 引入封装好的打印函数
import printHtml from "./printHtml.js";
import { ref } from 'vue';
let oldStr = ref(false);
let editableIs = ref(true);
let showChang = ref(true);
let list = [{
name: "阿哒",
age: 26,
sex: "男",
phone: "12345678901",
mail: "mmm@mmm.com",
address: "蓝星星国马尔哈哈海岛",
workAge: 2,
jobs: "研发",
salary: "1.8k"
},
{
name: "阿荣",
age: 24,
sex: "男",
phone: "12345678901",
mail: "mmm@mmm.com",
address: "蓝星星国马尔哈哈海岛",
workAge: 1,
jobs: "研发",
salary: "1.8k"
},
{
name: "阿豪",
age: 26,
sex: "男",
phone: "12345678901",
mail: "mmm@mmm.com",
address: "蓝星星国马尔哈哈海岛",
workAge: 5,
jobs: "产品",
salary: "1.8k"
},
{
name: "阿晨",
age: 29,
sex: "男",
phone: "12345678901",
mail: "mmm@mmm.com",
address: "蓝星星国马尔哈哈海岛",
workAge: 9,
jobs: "设计",
salary: "1.8k"
},
{
name: "阿震",
age: 30,
sex: "男",
phone: "12345678901",
mail: "mmm@mmm.com",
address: "蓝星星国马尔哈哈海岛",
workAge: 7,
jobs: "销售",
salary: "1.8k"
},
{
name: "阿锋",
age: 21,
sex: "男",
phone: "12345678901",
mail: "mmm@mmm.com",
address: "蓝星星国马尔哈哈海岛",
workAge: 0.1,
jobs: "售后",
salary: "1.8k"
}
]
// 点击处理打印
const onPrint = () => {
editableIs.value = false;
//以上用于关闭不需要打印的部分 最简单的方法是给dom v-if,不需要赘述吧
showChang.value = true;
//双向绑定需要给页面渲染时间,延迟一定时间
setTimeout(function () {
// document.title = '标题 | 这是页眉标题哦';
// 获取body的内容
let oldStr = window.document.body.innerHTML;
// 开始打印标识, 21个字符 注意""
let start = '<i test="printStart">';
// 结束打印标识, 23个字符
let end = '<i test="printEnt"></i>';
let condition = true
let printData = ''
while (condition) {
if (oldStr.indexOf(start) == -1) {
condition = false
} else {
// 截取开始打印标识之后的内容
let newStr = oldStr.substr(oldStr.indexOf(start) + 21);
// 截取开始打印标识和结束打印标识之间的内容
printData = printData + newStr.substring(0, newStr.indexOf(end));
// 截取结束打印标识之后的内容
oldStr = newStr.substr(newStr.indexOf(end) + 23);
}
}
let reg = new RegExp("display: none", "g"); //定义正则表达式
printData = printData.replace(reg, '')
// 调用打印
printHtml(printData)
}, 500)
}
</script>
<style scoped>
.xwtable {
width: 100%;
border-collapse: collapse;
border: 1px solid #ccc;
}
.xwtable thead td {
font-size: 12px;
color: #333333;
text-align: center;
background: url(table_top.jpg) repeat-x top center;
border: 1px solid #ccc;
font-weight: bold;
}
.xwtable tbody tr {
background: #fff;
font-size: 12px;
color: #666666;
}
.xwtable tbody tr.alt-row {
background: #f2f7fc;
}
.xwtable td {
line-height: 20px;
text-align: left;
padding: 4px 10px 3px 10px;
height: 18px;
border: 1px solid #ccc;
}
</style>
3、使用vue3-print-nb依赖
这个方法可以自定义打印区域,并且保留原有样式,缺点是打印区域的样式不能和打印区域外的样式相关联。同事我们也可以在通过@media print
来对需要打印的区域进行样式设置,自由度比较好一些,具体更多使用方式还是大家一起去发掘。
这里使用的是vue3+ts的引入和使用方式,vue2的引入方式可以去看看别的文章。
3.1、全局引入方式
// main.ts
import { createApp } from "vue";
import App from "./App.vue";
import Print from 'vue3-print-nb'
createApp(App).use(Print).mount("#app");
3.2、局部引入方式(setup)自定义指令--------------(推荐)
网上有很多<script lang="ts">
或者<script>
的使用自定义指令的方式这里就不再赘述了。
<script setup lang="ts">
import print from 'vue3-print-nb'
// 使用自定义指令
const vPrint = print
let prints = {
id: 'print-iframe',
popTitle: '配置页眉标题', // 打印配置页上方的标题
extraHead: '', // 最上方的头部文字,附加在head标签上的额外标签,使用逗号分割
preview: false, // 是否启动预览模式,默认是false
previewTitle: '预览的标题', // 打印预览的标题
previewPrintBtnLabel: '预览结束,开始打印', // 打印预览的标题下方的按钮文本,点击可进入打印
zIndex: 20002, // 预览窗口的z-index,默认是20002,最好比默认值更高
previewBeforeOpenCallback() { console.log('正在加载预览窗口!'); }, // 预览窗口打开之前的callback
previewOpenCallback() { console.log('已经加载完预览窗口,预览打开了!') }, // 预览窗口打开时的callback
// 开始打印之前的callback
beforeOpenCallback() {
console.log('开始打印之前!')
},
openCallback() { console.log('执行打印了!') }, // 调用打印时的callback
closeCallback() { console.log('关闭了打印工具!'); var element = document.getElementById("print-iframe"); element?.parentNode?.removeChild(element); }, // 关闭打印的callback(无法区分确认or取消)
clickMounted() { console.log('点击v-print绑定的按钮了!') },
standard: '',
extarCss: ''
}
</script>
3.3、简单直接使用场景
我们在需要打印的html标签上添加在
prints
对象里定义的id属性 ,通过在按钮加上v-print="prints"
自定义指令实现打印。
<template>
<button v-print="prints">打印2</button>
<div id="print-iframe">
// dom部分 可用if控制
<div class="xwtable">
<table>
<tr>
<th>序号</th>
<th>姓名</th>
<th>年龄</th>
<th>性别</th>
<th>手机</th>
<th>邮箱</th>
<th>地址</th>
<th>工龄</th>
<th>岗位</th>
<th>薪资</th>
</tr>
<tr v-for="(item, index) in list"
key="index">
<td>{{ index + 1}}</td>
<td>{{ item.name }}</td>
<td>{{ item.age }}</td>
<td>{{ item.sex }}</td>
<td>{{ item.phone }}</td>
<td>{{ item.mail }}</td>
<td>{{ item.address }}</td>
<td>{{ item.workAge }}</td>
<td>{{ item.jobs }}</td>
<td>{{ item.salary }}</td>
</tr>
</table>
</div>
<div>
<div class="text_styte">我是测试样式的</div>
</div>
</div>
</template>
<script setup lang="ts">
// 引入封装好的打印函数
import print from 'vue3-print-nb'
import { ref } from 'vue';
const vPrint = print
let prints = {
id: 'print-iframe',
popTitle: '配置页眉标题', // 打印配置页上方的标题
extraHead: '', // 最上方的头部文字,附加在head标签上的额外标签,使用逗号分割
preview: false, // 是否启动预览模式,默认是false
previewTitle: '预览的标题', // 打印预览的标题
previewPrintBtnLabel: '预览结束,开始打印', // 打印预览的标题下方的按钮文本,点击可进入打印
zIndex: 20002, // 预览窗口的z-index,默认是20002,最好比默认值更高
previewBeforeOpenCallback() { console.log('正在加载预览窗口!'); }, // 预览窗口打开之前的callback
previewOpenCallback() { console.log('已经加载完预览窗口,预览打开了!') }, // 预览窗口打开时的callback
// 开始打印之前的callback
beforeOpenCallback() {
console.log('开始打印之前!')
},
openCallback() { console.log('执行打印了!') }, // 调用打印时的callback
closeCallback() { console.log('关闭了打印工具!'); var element = document.getElementById("print-iframe"); element?.parentNode?.removeChild(element); }, // 关闭打印的callback(无法区分确认or取消)
clickMounted() { console.log('点击v-print绑定的按钮了!') },
standard: '',
extarCss: ''
}
let list = [{
name: "阿哒",
age: 26,
sex: "男",
phone: "12345678901",
mail: "mmm@mmm.com",
address: "蓝星星国马尔哈哈海岛",
workAge: 2,
jobs: "研发",
salary: "1.8k"
},
{
name: "阿荣",
age: 24,
sex: "男",
phone: "12345678901",
mail: "mmm@mmm.com",
address: "蓝星星国马尔哈哈海岛",
workAge: 1,
jobs: "研发",
salary: "1.8k"
},
{
name: "阿豪",
age: 26,
sex: "男",
phone: "12345678901",
mail: "mmm@mmm.com",
address: "蓝星星国马尔哈哈海岛",
workAge: 5,
jobs: "产品",
salary: "1.8k"
},
{
name: "阿晨",
age: 29,
sex: "男",
phone: "12345678901",
mail: "mmm@mmm.com",
address: "蓝星星国马尔哈哈海岛",
workAge: 9,
jobs: "设计",
salary: "1.8k"
},
{
name: "阿震",
age: 30,
sex: "男",
phone: "12345678901",
mail: "mmm@mmm.com",
address: "蓝星星国马尔哈哈海岛",
workAge: 7,
jobs: "销售",
salary: "1.8k"
},
{
name: "阿锋",
age: 21,
sex: "男",
phone: "12345678901",
mail: "mmm@mmm.com",
address: "蓝星星国马尔哈哈海岛",
workAge: 0.1,
jobs: "售后",
salary: "1.8k"
}
]
// 点击处理打印
</script>
<style scoped>
.xwtable {
width: 100%;
border-collapse: collapse;
border: 1px solid #ccc;
}
.xwtable thead td {
font-size: 12px;
color: #333333;
text-align: center;
background: url(table_top.jpg) repeat-x top center;
border: 1px solid #ccc;
font-weight: bold;
}
.xwtable tbody tr {
background: #fff;
font-size: 12px;
color: #666666;
}
.xwtable tbody tr.alt-row {
background: #f2f7fc;
}
.xwtable td {
line-height: 20px;
text-align: left;
padding: 4px 10px 3px 10px;
height: 18px;
border: 1px solid #ccc;
}
</style>
3.4、在打印前处理需要打印的内容区域
- 在触发打印前我们需要做一些事情,我们可以通过创建两个button标签点击触发处理事件后在执行打印功能。
- 并且我们也可以创建一个新的dom节点去存放相要打印的内容,重新渲染到页面上再执行打印。
<template>
<div>
<button ref="printRef" v-print="prints">打印2</button>
<button @click="onClick">打印3</button>
<div id="printArea">
<div class="text_styte">我是测试样式的</div>
<Auto></Auto>
</div>
</div>
</template>
<script setup lang="ts">
import Auto from "./Auto.vue";
import print from 'vue3-print-nb'
import { ref } from 'vue';
const vPrint = print
let printRef = ref();
let prints = {
id: 'print-iframe',
popTitle: '配置页眉标题', // 打印配置页上方的标题
extraHead: '', // 最上方的头部文字,附加在head标签上的额外标签,使用逗号分割
preview: false, // 是否启动预览模式,默认是false
previewTitle: '预览的标题', // 打印预览的标题
previewPrintBtnLabel: '预览结束,开始打印', // 打印预览的标题下方的按钮文本,点击可进入打印
zIndex: 20002, // 预览窗口的z-index,默认是20002,最好比默认值更高
previewBeforeOpenCallback() { console.log('正在加载预览窗口!'); }, // 预览窗口打开之前的callback
previewOpenCallback() { console.log('已经加载完预览窗口,预览打开了!') }, // 预览窗口打开时的callback
// 开始打印之前的callback
beforeOpenCallback() {
console.log('开始打印之前!')
},
openCallback() { console.log('执行打印了!') }, // 调用打印时的callback
closeCallback() { console.log('关闭了打印工具!'); var element = document.getElementById("print-iframe"); element?.parentNode?.removeChild(element); }, // 关闭打印的callback(无法区分确认or取消)
clickMounted() { console.log('点击v-print绑定的按钮了!') },
standard: '',
extarCss: ''
}
const onClick = () => {
test()
printRef.value.click()
}
const test = () => {
let iframe = document.createElement("div");
iframe.setAttribute("id", "print-iframe");
iframe.setAttribute(
"style",
"width: 100%; height: 100%; z-index: -9999; border: 0; margin: 0; padding: 0; "
);
// 创建节点
document.body.appendChild(iframe);
//获取目标节点
let targetDom = document.getElementById("printArea");
console.log(targetDom);
let temp = `<div class="text_styte">我是测试样式的22222222222</div> <div id="pageFooter">Page </div>`;
temp += targetDom?.innerHTML
temp += targetDom?.innerHTML
temp += targetDom?.innerHTML
temp += targetDom?.innerHTML
temp += targetDom?.innerHTML
temp += targetDom?.innerHTML
temp += targetDom?.innerHTML
iframe.innerHTML = temp
}
</script>
本篇文章主要介绍如何使用,文笔描述不好,大家见谅。。。
更多推荐
已为社区贡献1条内容
所有评论(0)