You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从URL加载的JS调用Electron函数?POS软件跨端打印实现

解决方案:Electron环境判断与跨环境打印逻辑调用

一、判断当前是否运行在Electron环境

直接检测全局对象的Electron特征,无需引入额外依赖:

function isElectron() {
  return typeof window !== 'undefined' && 
         (typeof process !== 'undefined' && process.versions?.electron) ||
         typeof window.require !== 'undefined';
}

二、从SPA调用Electron端打印函数的两种方法

方法1:使用预加载脚本(Preload)暴露安全API(推荐)

Electron的上下文隔离模式下,预加载脚本是连接渲染进程(SPA)和主进程的安全通道,步骤如下:

  1. Electron主进程配置预加载脚本
    在创建BrowserWindow时指定preload路径,并注册IPC处理函数:
// main.js(Electron主进程)
const { app, BrowserWindow, ipcMain } = require('electron');
const path = require('path');
const escpos = require('escpos'); // 你的ESCPOS库

// 处理打印请求的主进程逻辑
ipcMain.handle('print-pos-data', async (event, printData) => {
  try {
    // 搜索USB打印机
    const printer = await escpos.USB.findPrinter();
    if (!printer) throw new Error('未找到可用USB打印机');
    
    const device = new escpos.USB(printer.vid, printer.pid);
    const printerInstance = new escpos.Printer(device);
    
    printerInstance.text(printData);
    printerInstance.cut();
    printerInstance.close();
    
    return { success: true };
  } catch (err) {
    return { success: false, error: err.message };
  }
});

function createWindow() {
  const mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
      contextIsolation: true, // 开启上下文隔离,安全最佳实践
      nodeIntegration: false // 禁用Node集成,避免安全风险
    }
  });

  mainWindow.loadURL('你的SPA部署地址'); // 加载外部SPA页面
}

app.whenReady().then(createWindow);
  1. 编写预加载脚本(preload.js)
    通过contextBridge将安全API暴露到SPA的全局对象:
// preload.js
const { contextBridge, ipcRenderer } = require('electron');

contextBridge.exposeInMainWorld('electronAPI', {
  printPOSData: (printData) => ipcRenderer.invoke('print-pos-data', printData)
});
  1. SPA中调用API
    判断环境后直接调用全局暴露的API:
// SPA业务代码
async function handlePrint(printData) {
  if (isElectron()) {
    const result = await window.electronAPI.printPOSData(printData);
    result.success ? alert('打印成功') : alert(`打印失败:${result.error}`);
  } else {
    // 浏览器端逻辑:下载打印数据为文件
    const blob = new Blob([printData], { type: 'text/plain' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = 'print-data.txt';
    a.click();
    URL.revokeObjectURL(url);
  }
}

方法2:直接使用IPC渲染器(不推荐,安全风险高)

如果禁用了上下文隔离(仅适合开发测试),可直接在SPA中引入ipcRenderer:

// SPA业务代码
async function handlePrint(printData) {
  if (isElectron()) {
    const { ipcRenderer } = window.require('electron');
    const result = await ipcRenderer.invoke('print-pos-data', printData);
    // 处理打印结果
  } else {
    // 浏览器端下载逻辑
  }
}

此方式会暴露Node API到渲染进程,存在XSS攻击风险,生产环境不建议使用。

三、更优实现方案:抽象打印适配器

为了让业务代码与运行环境解耦,抽象统一的打印接口,不同环境加载对应实现:

  1. 定义统一接口
// print-adapter.js
export default class PrintAdapter {
  async print(printData) {
    throw new Error('请实现print方法');
  }
}
  1. Electron环境实现
// electron-print-adapter.js
import PrintAdapter from './print-adapter.js';

export default class ElectronPrintAdapter extends PrintAdapter {
  async print(printData) {
    return window.electronAPI.printPOSData(printData);
  }
}
  1. 浏览器环境实现
// browser-print-adapter.js
import PrintAdapter from './print-adapter.js';

export default class BrowserPrintAdapter extends PrintAdapter {
  async print(printData) {
    const blob = new Blob([printData], { type: 'text/plain' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = 'print-data.txt';
    a.click();
    URL.revokeObjectURL(url);
    return { success: true };
  }
}
  1. 业务代码中使用
// 初始化适配器
let printAdapter;
if (isElectron()) {
  printAdapter = new ElectronPrintAdapter();
} else {
  printAdapter = new BrowserPrintAdapter();
}

// 统一调用打印
async function handlePrint(printData) {
  const result = await printAdapter.print(printData);
  // 统一处理打印结果
}

这种方式让业务代码无需关心运行环境,后续新增平台(如移动端)只需添加对应适配器即可。

内容的提问来源于stack exchange,提问作者Crazynds

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 09:22:42