记一次Electron+vue实现动态打印小票

1.业务场景

    公司有做一个Electron+Vue的收银产品,收银以后需要将订单信息通过小票打印出来,记录一下做这个需求遇到的一些问题跟bug

2.解决思路

    通过webview或者新窗口将需要打印的内容渲染,然后通过webcontents.print这个api将页面内容输出到小票机然后静默打印

 3.代码实现

        3.1  渲染进程触发打印

        这个代码使用vue3+electron实现,但是为了方便项目的维护以及解决前期web页面更新客户端也需要更新的问题,客户端代码跟webPage被我架构成了两个项目,所以这里的ipc是通过window来暴露出来。点击打印的时候将配置以及需要打印的数据传到主进程。

// 处理点击打印的事件
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>

这里直接用了两个定时器来保证加载页面时数据能被接收到以及打印时页面能被渲染完成,虽然是笨方法,但是主要还是实现功能为主。一开始想的是mainWindow页面跟printWindow的页面都是一个项目可以直接使用vuex来保存,但是创建了新窗口之后,新窗口的vuex是重新实例化出来的,获取不到值,然后就直接通过ipc传到主进程再打印时将数据传回Print页面。不过怎么传数据不是很重要,你甚至可以通过localStorage,数据库等持久化一个数据打印之后再删除都行。

4.bug

NOTICE:之前使用的electron版本是19.0,反复尝试调用print这个api都会报错,后面换成了最新的19.0.8版本bug被修复,另外,我还发现electron17的版本里面窗口的拉伸会失效或者鬼畜。

这里的两个setTimeout 很是碍眼,哪天有空了优化成promise

为什么使用BrowserWindow来实现而不是使用webview?webview你还需要去再写一个html的静态文件来当作你打印的结构,直接使用BrowserWindow我直接打印vue的结构更简单

补充一下,项目里面的打印机列表是通过配置来管理的,打印小票直接就给主进程传小票机的名字进行静默打印。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要在 Electron + Vue实现截图,你可以使用 Electron 中的 desktopCapturer 模块来获取屏幕截图。以下是一些步骤: 1. 在你的 Vue 组件中引入 Electron 模块: ```javascript const { desktopCapturer } = require('electron') ``` 2. 创建一个函数来获取屏幕截图。这个函数可以使用 desktopCapturer 模块来获取桌面上的媒体源并将其转换为可用的图像。在这个函数中,你可以使用 Canvas API 或其他图像处理库来对图像进行操作。 ```javascript async function captureScreen() { const sources = await desktopCapturer.getSources({ types: ['screen'] }) const source = sources[0] const stream = await navigator.mediaDevices.getUserMedia({ audio: false, video: { mandatory: { chromeMediaSource: 'desktop', chromeMediaSourceId: source.id, minWidth: 1280, maxWidth: 1280, minHeight: 720, maxHeight: 720 } } }) const videoTrack = stream.getVideoTracks()[0] const imageCapture = new ImageCapture(videoTrack) const bitmap = await imageCapture.grabFrame() // 在这里对 bitmap 进行处理 } ``` 3. 在你的 Vue 组件中创建一个函数来触发屏幕截图函数,并将截图显示在页面上。你可以使用 canvas 元素来显示图像。 ```javascript methods: { async takeScreenshot() { const canvas = this.$refs.canvas const context = canvas.getContext('2d') context.clearRect(0, 0, canvas.width, canvas.height) const bitmap = await captureScreen() canvas.width = bitmap.width canvas.height = bitmap.height context.drawImage(bitmap, 0, 0) } } ``` 4. 在你的 Vue 组件中添加一个 canvas 元素来显示截图: ```html <canvas ref="canvas"></canvas> ``` 这样就可以在 Electron + Vue实现截图了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值