使用electron开发应用遇到了打印小票的功能,实现途中还是几经波折。开始选择了c-lodop这个web打印插件,该说不说啊这个用着是挺方便,他们的服务很多东西也完善,web可以直接打印html,静默打印不用弹出浏览器的打印界面,但打印出来的会有c-lodop的水印 本页由【试用版打印控件...】 。
需要换一种实现了,查到electron有静默打印的方式有两种
第一种:通过window的webcontent对象,使用此种方式需要单独开出一个打印的窗口,可以将该窗口隐藏,但是通信调用相对复杂
第二种:使用页面的webview元素调用打印,可以将webview隐藏在调用的页面中,通信方式比较简单。
第二种比较适合我的场景 在electron3.0版本实现还挺简单的例子-这里,强调是electron的版本是3.0,在版本升级中有些功能被关闭了,比如webview,webview中使用node模块等错误报的你很是难受。
接下来展示我报错到最后成功的辛酸历程,我的electron是13,希望能对你有所帮助。
将例子的printer.vue和print.html组件放入你的项目中,放哪可以自己定,print.html可以放到public中方便调用。
background.js
let win = new BrowserWindow({
width: 970,
height: 800,
// fullscreen: true, //全屏
// show: false,
webPreferences: {
contextIsolation:false, //上下文隔离
enableRemoteModule: true, //启用远程模块
nodeIntegration: true, //开启自带node环境
webviewTag: true, //开启webview
webSecurity: false,
allowDisplayingInsecureContent: true,
allowRunningInsecureContent: true,
},
// useContentSize: true,
frame: false, //客户端窗口顶部菜单去掉
});
print.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<style>
body,
html {
padding: 0;
margin: 0;
font-size: 30px;
}
@page {
margin: 0px;
}
.div1 {
overflow: hidden;
}
</style>
</head>
<body id="bd" style="padding-left: 5px;box-sizing: border-box;"></body>
<script>
const { ipcRenderer } = require('electron')
ipcRenderer.on('webview-print-render', (event, info) => {
// 执行渲染
console.log(JSON.stringify(info));
document.getElementById('bd').innerHTML = info.html
ipcRenderer.sendToHost('webview-print-do')
})
</script>
<style>
#bd{
}
</style>
</html>
printer.vue也可以自己写,为了跑通可以直接指定打印机名字,直接调用打印方法
<template>
<div class="container">
<webview id="printWebview" ref="printWebview" :src="fullPath" nodeintegration />
</div>
</template>
<script>
import config from "@/utils/config";
let fullPath = '',ipc;
if (config.type != "loc") {
const { ipcRenderer } = require("electron");
ipc = ipcRenderer;
fullPath = '/print.html';
// fullPath = path.join(__static, 'print.html');
} else {
fullPath = "";
}
export default {
name: 'Pinter',
components: {
data() {
return {
printDeviceName: '80mm Series Printer',
fullPath: fullPath,
messageBox: null,
htmlData: ''
}
},
mounted() {
const webview = this.$refs.printWebview;
webview.addEventListener('console-message', e => {
//可以打印出webview中所需要打印的内容
console.log('webview: ' + e.message);
});
webview.addEventListener('ipc-message', (event) => {
if (event.channel === 'webview-print-do') {
webview.print(
{
silent: true,
printBackground: true,
deviceName: this.printDeviceName
},
(data) => {
this.messageBox.close()
if (data) {
this.$emit('complete')
} else {
this.$emit('cancel')
}
},
)
}
})
},
methods: {
print(val) {
this.htmlData = val
console.log("print");
this.printRender();
// this.getPrintListHandle()
},
printRender(html) {
this.messageBox = this.$message({
message: '打印中,请稍后',
duration: 0
})
// 获取<webview>节点
const webview = this.$refs.printWebview
// 发送信息到<webview>里的页面
webview.send('webview-print-render', {
printName: '80mm Series Printer',
html: `小人物有大智慧`
})
}
}
}
</script>
<style scoped>
.container {
position: fixed;
right: -500px;
}
</style>
一切都好像那么的合理且完美,当我平静的点击了运行
没有node模块,难道... 官网欺骗了我,print.html中不能没有node那ipcRenderer得通信不就不能实现了,直接把地址指向print.html,node模块有,说明webview加载不能获取到node模块,这一顿百度,在一个文章中找到另一个配置参数
<webview id="printWebview" ref="printWebview" :src="fullPath" nodeintegration webpreferences="contextIsolation=no"/>
遂整之,既出,喜之,疑又现?-?
打印已经进到了print.html的监听中 查了下文档webview.print()的结构已经换了
一堆参数,作为一个中本英语水平的我看出了他只有一个参数加第二个报错了,并刀中了最后的返回是个promise,直接就返回成功还是失败了 修改下
webview.addEventListener('ipc-message', (event) => {
if (event.channel === 'webview-print-do') {
webview.print({
silent: true,
printBackground: true,
deviceName: '80mm Series Printer'
}).then((res) => {
})
.catch((err) => {
})
.finally(() => {
this.messageBox.close()
});
}
})
run 走你
之后就是设置模板替换数据了 嗯 真棒!!!!