1. ビジネスシナリオ
同社は Electron+Vue のレジ製品を持っており、レジの後、レシートを通じて注文情報を印刷する必要があり、このデマンドで発生した問題やバグを記録する必要があります。
2. ソリューション
webview または新しいウィンドウを介して印刷するコンテンツをレンダリングし、webcontents.print API を介してページ コンテンツを小型券売機に出力し、サイレントに印刷します。
3. コードの実装
3.1 レンダリング プロセスが印刷をトリガーする
このコードは vue3+electron を使用して実装されていますが、プロジェクトのメンテナンスを容易にし、初期段階で Web ページが更新されるとクライアントも更新する必要があるという問題を解決するために、クライアント コードと webPage は次のような構造になっています。私による 2 つのプロジェクトなので、ここの IPC は窓越しに表示されます。[印刷] をクリックすると、印刷する構成とデータがメイン プロセスに送信されます。
// 处理点击打印的事件
const handlePrint = () => {
const { ipcRenderer } = window.require('electron')
ipcRenderer.invoke("my-print", JSON.stringify({
option: {
silent: true,
deviceName: store.state?.config?.defaultLittlePrinter,
printBackground: true,
margins: {
marginType: "none"
},
scaleFactor: 80,
},
data: {
orderDetail: state.orderDetail
}
}));
}
3.2 メイン プロセスがイベントを受信して処理する
メイン プロセスは、my-print イベントを受信した後、ウィンドウの作成を開始します。
ipcMain.handle('my-print', (event, params) => {
this.createPrintWindow(JSON.parse(params))
});
ウィンドウを作成する createPrintWindow コード
createPrintWindow(params) {
// 实例化一个窗口出来
this.printWindow = new BrowserWindow({
width: 150,
minHeight: 100,
frame: false,
skipTaskbar: true,
transparent: true,
resizable: false,
show: false, //不要让窗口显示出来
webPreferences: {
contextIsolation: false,
webviewTag: true,
nodeIntegration: true,
webSecurity: false,
}
})
// 让窗口去加载webPage里面的某个路由
this.printWindow.loadURL("http://localhost:3001/#/print")
// 页面加载完成了就可以执行打印的流程了
this.printWindow.once('ready-to-show', async () => {
setTimeout(() => {
this.printWindow.webContents.send('getPrinterData', params.data.orderDetail);
}, 100);
setTimeout(() => {
this.printWindow.webContents.print(params.option, (success: boolean, failureReason: string) => {
this.printWindow.destroy()
this.printWindow = null
})
}, 1000);
})
}
読み込まれた locahost:3001/print コード
<script setup>
import { ref } from "vue"
import { useStore } from "vuex"
const store = useStore()
const orderDetail = ref()
const { ipcRenderer } = window.require("electron")
ipcRenderer.once("getPrinterData", (event, data) => {
orderDetail.value = data
});
</script>
ここでは、2 つのタイマーを直接使用して、ページの読み込み時にデータを受信できるようにし、印刷時にページをレンダリングできるようにします。最初に思ったのは、mainWindow ページと printWindow ページはどちらも vuex を使って直接保存できるプロジェクトなのですが、新しいウィンドウを作成した後、新しいウィンドウの vuex が再インスタンス化され、値が取得できないということでした。 、次に ipc を介して直接データをメインプロセスに渡して印刷するときに、データを印刷ページに戻します。しかし、データを転送する方法はそれほど重要ではありません。localStorage、データベースなどを介してデータを保持し、印刷してから削除することもできます。
4.バグ
注: 以前使用していた electron のバージョンは 19.0 でした。印刷 API を繰り返し呼び出すと、エラーが報告されました。後で、最新バージョンの 19.0.8 に置き換えました。.
ここでの 2 つの setTimeouts は非常に目を引くものです。時間があれば、promise に最適化してください。
webview を使用する代わりに BrowserWindow を使用して実装するのはなぜですか? webview の場合、出力する構造体として静的な html ファイルも記述する必要があります.BrowserWindow を使用して vue の構造体を直接出力する方が簡単です.
さらに、プロジェクト内のプリンターのリストは構成によって管理され、小さなチケットを印刷するときに、小さなチケット マシンの名前がサイレント印刷のメイン プロセスに直接渡されます。