思路
在electron-react项目当中要实现打印部分页面内容的需求,
第一种方法是使用iframe标签打印,这种方法最简单网上有很多教程,使用iframe.contentWindow.print()
这个方法会弹出打印对话框,我还没有找到关闭的方法,所以没有采用。
第二种方法是在使用electron的主线程调用webContents.print()
方法,这个方法相对比较复杂,主线程和渲染线程之间需要通信。
流程如下:
主线程 :A 渲染线程:B
1.B
发送获取打印机列表的请求,
2.A
响应渲染线程的请求,获取到打印机列表过后发给 B
,
3.B
收到打印机列表过后进行数据处理选择一个打印机准备开始打印
4.B
把设计好的打印页面data
发送给 A
准备开始打印
5. A
收到打印请求过后 创建一个新的浏览器窗口,把 B
发过来的data
渲染到打印窗口里面,开始打印 ,打印成功过后 关闭打印窗口。
整个过程就是这样。
特别注意
进程之间的通信监听的事件要区分on和once的使用,如在渲染进程中的函数
getPrint()
,startPrint()
,这两个函数会重复调用,函数里面的监听事件应该用once
而不是on
,因为每一次执行函数都会去挂载一个监听事件,使用on
会一直挂载不会自动销毁,如果你调用了n次getPrint
函数将会有n个同一种监听事件被挂载,按照常规的逻辑应该是一种监听事件应该只挂载一个才对。
主线程设计思路
在主线程中需要做的事情:
1.获取打印机列表
2.实例化一个新的浏览器窗口用于打印
3.打印结束过后需要关闭这个打印窗口
在主线程和渲染线程之间用ipcMain.on
方法监听对方发出的事件
ipcMain.on('getPrinterList', () => {
1 // 主线程获取打印机列表
const list = mainWindow.webContents.getPrinters();
// 通过webContents发送事件到渲染线程,同时将打印机列表也传过去
mainWindow.webContents.send('allPrinterList', list);
});
ipcMain.on('printStart', (_event, obj) => {
2 const printWindow = new BrowserWindow({ // 实例化一个新的浏览器窗口用于打印
webPreferences: {
nodeIntegration: true,
webSecurity: false,
enableRemoteModule: true
},
show: false,
width: size.width,
height: size.height,
fullscreenable: true,
minimizable: false
});
// 打印窗口添加html页面
printWindow.loadURL(`data:text/html;charset=utf-8,${encodeURI(obj.html)}`);
printWindow.webContents.once('did-finish-load', () => { // 等待页面加载完成过后再打印
printWindow.webContents.print({
silent: true, // 不显示打印对话框
printBackground: true, // 是否打印背景图像
deviceName: obj.deviceName
}, (success: boolean, failureReason: string) => {
mainWindow.webContents.send('res', { success, failureReason });
3 printWindow.close();// 打印过后关闭该窗口
});
});
});
渲染进程设计思路
1.通过获取打印机列表按钮发送一个请求到主线程获取打印机列表
2.把想要打印的内容发给主线程进行打印
import { ipcRenderer } from 'electron';
// 获取打印机列表
const printList = [];
const printWebview = useRef(null); //获取dom节点
function getPrint() {
1 ipcRenderer.send('getPrinterList');
console.log('发送获取打印机列表事件');
// 监听主线程发送打印机列表的事件
ipcRenderer.once('allPrinterList', (event, data) => {
printList = data;
// console.log(data); // data就是返回的打印机数据列表
});
}
// 打印程序
function startPrint(obj) { // obj 是打印机对象
console.log(obj);
const printStyle = '<style>@page{margin:0}</style>';
const printData = {
deviceName: obj[1].name, // 打印机名称
html: printStyle + printWebview.current.innerHTML // 你需要打印的内容
};
2 ipcRenderer.send('printStart', printData);
// 监听主线程发送的打印结果的事件
ipcRenderer.once('res', (_e, data) => {
// console.warn(e);
console.log('执行完打印程序', data);
});
}