本文主要介绍了electron如何获取本地打印机,并且连接打印机进行打印
这里我用的是vue3,react或者vue2用户可自行根据代码来转换风格
1.打印机渲染在渲染进程,获取的话只能在主进程来获取
1.1 主进程获取-background.js
import
let win
// 通过检查第二个实例启动时的事件来避免多个实例运行
const gotTheLock = app.requestSingleInstanceLock()
async function createWindow() {
const config = {
...winState.winOptions,
minWidth: 400, // 设置最小宽度
webPreferences: {
contextIsolation: false,
enableRemoteModule: true,
nodeIntegration: true,
webSecurity: false, //允许跨域访问本地图片
webviewTag: true,
},
}
Menu.setApplicationMenu(null) // null值取消顶部菜单栏
win = new BrowserWindow(config)
if (process.env.WEBPACK_DEV_SERVER_URL) {
// Load the url of the dev server if in development mode
await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
if (!process.env.IS_TEST) win.webContents.openDevTools()
} else {
createProtocol('app')
// Load the index.html when not in development
win.loadURL('app://./index.html')
}
winState.manage(win)
}
app.on('ready', async () => {
if (!gotTheLock) {
app.quit()
} else {
app.on('second-instance', (event, commandLine, workingDirectory) => {
if (win) {
if (win.isMinimized()) {
win.restore()
}
win.focus()
}
})
createWindow()
// 在electron启动后注册所有的主进程ipc事件
electronApiInit()
win.on('closed', () => {
win = null
})
}
})
// 主进程注册事件
function electronApiInit() {
try {
process.env.WEBPACK_DEV_SERVER_URL && win.setIcon(path.join(__dirname, `../public/favicon.png`))
electronInit.initPrintList(win)
} catch (error) {
dialog.showErrorBox('ElectronApiInit', JSON.stringify(error.message))
}
}
1.2 注册获取本地打印机事件
import
export const initPrintList = (win) => {
ipcMain.handle('getPrintList', async (event, isShowMessage) => {
try {
// 在background.js里把win对象传递进来,通过win的webContents的getPrintersAsync方法获取到本地打印机,在渲染进程进行读取
const list = await win.webContents.getPrintersAsync()
return list
} catch (error) {
console.log('error', error)
}
})
}
1.3渲染进程读取本地打印机数组(vue文件或者jsx文件)
javascript
<div v-for="item in systemPrintList" :key="item.name">
<div :class="['p-x-10', item.isActive ? 'header-active' : 'header-max']" @click="setActiveItem(item)" >{{ item.name }}</div>
</div>
const { ipcRenderer } = require('electron')
import {ref} from 'vue'
const printList = ref([])
// 这个函数写到vue文件的methods里
async getPrintList({ commit }, data) {
const list = await ipcRenderer.invoke('getPrintList', data)
list.forEach((l) => {
// isDefault字段是返回自带的,代表着当前哪台打印机处于活跃状态
l.isActive = l.isDefault
})
printList.value = list
console.log('list', list)
}
// 设置当前活跃的打印机
const setActiveItem = (item) => {
printList.value.forEach((f) => {
f.isActive = f.name === item.name
})
}
到这步为止,已经可以获取到本地打印机,如果方便别的地方读取,可以存储到vuex/pinia/redux里
2.实现打印
electron的打印主要可以分为两种,一种是webContents的print方法,另一种是webview的打印,这里我们使用的是webContents的打印
2.1 获取webContents
要获取到webContents,首先需要获取到win。win在BrowserWindow可以拿到,因为打印是不能覆盖我们现有的electron页面,所以需要new一个新的BrowserWindow对象并且设置为show:false,我们可以封装一个print函数,打印的方法和函数之类的都可以写到这个函数里,这里我简单封装一个
//
import { ipcMain, BrowserWindow } from 'electron'
export default function usePrint() {
/**主窗体的win对象 */
ipcMain.on('handle_print', (e, { htmlText, deviceName }) => {
// 创建一个新的隐藏窗口,用于打印
let printWindow = new BrowserWindow({ show: false, width: 1920, height: 1080, contextIsolation: false, enableRemoteModule: true, nodeIntegration: true, webSecurity: false })
printWindow.loadURL('data:text/html,' + encodeURIComponent(htmlText))
printWindow.webContents.print({ deviceName, silent: true })
})
}
2.2 初始化主进程函数
//
import { app, protocol, BrowserWindow, Menu, dialog } from 'electron'
import usePrint from './electron-service/ipc/usePrint'
let win
async function createWindow() {
const config = {
...winState.winOptions,
minWidth: 400, // 设置最小宽度
webPreferences: {
contextIsolation: false,
enableRemoteModule: true,
nodeIntegration: true,
webSecurity: false, //允许跨域访问本地图片
webviewTag: true,
},
}
Menu.setApplicationMenu(null) // null值取消顶部菜单栏
win = new BrowserWindow(config)
winState.manage(win)
}
app.on('ready', async () => {
if (!gotTheLock) {
app.quit()
} else {
app.on('second-instance', (event, commandLine, workingDirectory) => {
if (win) {
if (win.isMinimized()) {
win.restore()
}
win.focus()
}
})
createWindow()
}
// 这里初始化print
usePrint()
})
2.3 渲染进程发送事件,主进程监听进行打印
><button @click="print">打印</button>
</template>
import { ipcRenderer } from 'electron'
// 这里我们使用html模板进行打印,deviceName为打印机名称,可以使用本地打印机名称,这里做测试用,所以我写死
const print = () => {
const printInfo = {
htmlText:
'<!doctype html><html lang=\'en\'><head><meta charset=\'utf-8\'><title>打印</title><style>*{box-sizing: border-box;} td{ word-break: break-all;}</style></head><body><div style=\'position: relative;width: 100%;height: 100%\'><div style=\'width:100%;min-height:25px;display:flex;flex-wrap:wrap;margin-left:0px;margin-right:0px;margin-Top:0px;margin-bottom:1px;\'><div style=\'display:block;word-break: break-all;flex: 0 0 33.33333336%;\'></div><div style=\'display:block;word-break: break-all;flex: 0 0 33.33333336%;\'><div style=\'font-size:18px;font-weight:normal;text-align:center;margin-left:0px;margin-right:0px;margin-Top:0px;margin-bottom:1px;\'>粤十-库存过户单</div></div><div style=\'display:block;word-break: break-all;flex: 0 0 33.33333336%;\'><div style=\'text-align:justify-start\'><img src=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAA8CAIAAABTvhANAAABKUlEQVR42u3TQQqAIBBA0bn/pQ0MShzHFq2E91dhZlq8aCcUvfviGdlPyNf51nLyuNT4VB6MoekV02rVs9VgddK8ybxCtbH8AX8eM+9hufJywueJpp+7WW3zBdohBYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIoCUIJQkkQShBKglCCUBKEEoSSIJQglAShBKEkCCUIJUEoQSgJQglCSRBKEEqCUIJQEoQShJLeLiIpS/zZp3V9AAAAAElFTkSuQmCC style=\'width:273px;height:70px;margin-left:0px;margin-right:0px;margin-Top:0px;margin-bottom:1px;\' /></div><div style=\'font-size:12px;font-weight:normal;text-align:center;margin-left:0px;margin-right:0px;margin-Top:0px;margin-bottom:1px;\'>GH-20230914-000005</div></div></div><div style=\'width:100%;min-height:25px;display:flex;flex-wrap:wrap;margin-left:0px;margin-right:0px;margin-Top:0px;margin-bottom:1px;\'><div style=\'display:block;word-break: break-all;flex: 0 0 50.000000039999996%;\'><div style=\'font-size:15px;font-weight:normal;text-align:left;margin-left:0px;margin-right:0px;margin-Top:0px;margin-bottom:1px;\'>过户单号:GH-20230914-000005</div><div style=\'font-size:15px;font-weight:normal;text-align:left;margin-left:0px;margin-right:0px;margin-Top:0px;margin-bottom:1px;\'>原货主:非标测试货主</div></div><div style=\'display:block;word-break: break-all;flex: 0 0 50.000000039999996%;\'><div style=\'font-size:15px;font-weight:normal;text-align:left;margin-left:0px;margin-right:0px;margin-Top:0px;margin-bottom:1px;\'>过户时间:</div><div style=\'font-size:15px;font-weight:normal;text-align:left;margin-left:0px;margin-right:0px;margin-Top:0px;margin-bottom:1px;\'>新货主:企业系统企业货主7</div></div></div><div style=\'margin-left:0px;margin-right:0px;margin-Top:0px;margin-bottom:1px;\'><table borderCollapse="collapse" border="none" style=\'font-size:15px;border-collapse:collapse;width:100%\'><thead><tr style=\'white-space: pre-wrap;\'><td style="border: solid #000 1px;height: undefinedpx;width: 30px; text-align: undefined">序号</td><td style="border: solid #000 1px;height: undefinedpx;width: 30px; text-align: undefined">商品名称</td><td style="border: solid #000 1px;height: undefinedpx;width: 30px; text-align: undefined">批次号</td><td style="border: solid #000 1px;height: undefinedpx;width: 30px; text-align: undefined">过户数量</td><td style="border: solid #000 1px;height: undefinedpx;width: 30px; text-align: undefined">库存数量</td><td style="border: solid #000 1px;height: undefinedpx;width: 30px; text-align: undefined">库存重量</td><td style="border: solid #000 1px;height: undefinedpx;width: 30px; text-align: undefined">过户重量</td><td style="border: solid #000 1px;height: undefinedpx;width: 30px; text-align: undefined">分配数量</td><td style="border: solid #000 1px;height: undefinedpx;width: 30px; text-align: undefined">可用数量</td><td style="border: solid #000 1px;height: undefinedpx;width: 30px; text-align: undefined">生产日期</td><td style="border: solid #000 1px;height: undefinedpx;width: 30px; text-align: undefined">失效日期</td><td style="border: solid #000 1px;height: undefinedpx;width: 30px; text-align: undefined">物料号</td><td style="border: solid #000 1px;height: undefinedpx;width: 30px; text-align: undefined">托盘号</td></tr></thead><tbody><tr style=\'height: undefinedpx;white-space: pre-wrap\'><td style="border: solid #000 1px; text-align: undefined">1</td><td style="border: solid #000 1px; text-align: undefined">高粱酒</td><td style="border: solid #000 1px; text-align: undefined">#000694</td><td style="border: solid #000 1px; text-align: undefined">2</td><td style="border: solid #000 1px; text-align: undefined">2</td><td style="border: solid #000 1px; text-align: undefined">2</td><td style="border: solid #000 1px; text-align: undefined">2</td><td style="border: solid #000 1px; text-align: undefined">0</td><td style="border: solid #000 1px; text-align: undefined">2</td><td style="border: solid #000 1px; text-align: undefined"></td><td style="border: solid #000 1px; text-align: undefined"></td><td style="border: solid #000 1px; text-align: undefined"></td><td style="border: solid #000 1px; text-align: undefined">TP202309134723</td></tr><tr style=\'height: undefinedpx;white-space: pre-wrap\'><td style="border: solid #000 1px; text-align: undefined">2</td><td style="border: solid #000 1px; text-align: undefined">150克冰袋,130个/框</td><td style="border: solid #000 1px; text-align: undefined">#000700</td><td style="border: solid #000 1px; text-align: undefined">33</td><td style="border: solid #000 1px; text-align: undefined">33</td><td style="border: solid #000 1px; text-align: undefined">643.5</td><td style="border: solid #000 1px; text-align: undefined">643.5</td><td style="border: solid #000 1px; text-align: undefined">0</td><td style="border: solid #000 1px; text-align: undefined">33</td><td style="border: solid #000 1px; text-align: undefined"></td><td style="border: solid #000 1px; text-align: undefined"></td><td style="border: solid #000 1px; text-align: undefined"></td><td style="border: solid #000 1px; text-align: undefined">TP202309144826</td></tr><tr style=\'height: undefinedpx;white-space: pre-wrap\'><td style="border: solid #000 1px; text-align: undefined"></td><td style="border: solid #000 1px; text-align: undefined"></td><td style="border: solid #000 1px; text-align: undefined">合计</td><td style="border: solid #000 1px; text-align: undefined">35</td><td style="border: solid #000 1px; text-align: undefined">35</td><td style="border: solid #000 1px; text-align: undefined">645.5</td><td style="border: solid #000 1px; text-align: undefined">645.5</td><td style="border: solid #000 1px; text-align: undefined"></td><td style="border: solid #000 1px; text-align: undefined"></td><td style="border: solid #000 1px; text-align: undefined"></td><td style="border: solid #000 1px; text-align: undefined"></td><td style="border: solid #000 1px; text-align: undefined"></td><td style="border: solid #000 1px; text-align: undefined"></td></tr></tbody></table></div><div style=\'font-size:15px;font-weight:normal;text-align:left;margin-left:0px;margin-right:0px;margin-Top:0px;margin-bottom:30px;\'>备注:</div><div style=\'width:100%;min-height:25px;display:flex;flex-wrap:wrap;margin-left:0px;margin-right:0px;margin-Top:0px;margin-bottom:1px;\'><div style=\'display:block;word-break: break-all;flex: 0 0 33.33333336%;\'><div style=\'font-size:15px;font-weight:normal;text-align:left;margin-left:0px;margin-right:0px;margin-Top:0px;margin-bottom:1px;\'>过户件数:45</div></div><div style=\'display:block;word-break: break-all;flex: 0 0 33.33333336%;\'><div style=\'font-size:15px;font-weight:normal;text-align:left;margin-left:0px;margin-right:0px;margin-Top:0px;margin-bottom:1px;\'>过户重量:840.5</div></div><div style=\'display:block;word-break: break-all;flex: 0 0 33.33333336%;\'><div style=\'font-size:15px;font-weight:normal;text-align:left;margin-left:0px;margin-right:0px;margin-Top:0px;margin-bottom:1px;\'>过户体积:0</div></div></div><div style=\'width:100%;min-height:25px;display:flex;flex-wrap:wrap;margin-left:0px;margin-right:0px;margin-Top:0px;margin-bottom:1px;\'><div style=\'display:block;word-break: break-all;flex: 0 0 25.000000019999998%;\'><div style=\'font-size:15px;font-weight:normal;text-align:left;margin-left:0px;margin-right:0px;margin-Top:0px;margin-bottom:1px;\'>审核人:</div><div style=\'font-size:15px;font-weight:normal;text-align:left;margin-left:0px;margin-right:0px;margin-Top:0px;margin-bottom:1px;\'>创建人:潇哥哥</div></div><div style=\'display:block;word-break: break-all;flex: 0 0 25.000000019999998%;\'><div style=\'font-size:15px;font-weight:normal;text-align:left;margin-left:0px;margin-right:0px;margin-Top:0px;margin-bottom:1px;\'>主管:</div></div><div style=\'display:block;word-break: break-all;flex: 0 0 25.000000019999998%;\'><div style=\'font-size:15px;font-weight:normal;text-align:left;margin-left:0px;margin-right:0px;margin-Top:0px;margin-bottom:1px;\'>原货主:非标测试货主</div></div><div style=\'display:block;word-break: break-all;flex: 0 0 25.000000019999998%;\'><div style=\'font-size:15px;font-weight:normal;text-align:left;margin-left:0px;margin-right:0px;margin-Top:0px;margin-bottom:1px;\'>新货主:企业系统企业货主7</div></div></div></div></body></html>',
deviceName: '皓诚达打印机',
}
ipcRenderer.send('handle_print', printInfo)
}
2.4 打印完成
此时查看打印队列发现已经发送过去并且完成打印
后续还会继续更新 electron实现打印机打印队列,控制本地打印机暂停/继续打印/删除打印,已经打印配置纸张,颜色等