1. 打印技术的核心价值

在桌面应用开发领域,打印功能是典型的"20%低频但80%关键"的功能模块。医疗机构需要即时打印检验报告、物流企业每天要处理大量面单、教育机构频繁输出准考证——这些场景都要求应用具备可靠的打印能力。Electron作为跨平台桌面开发框架,其打印系统的设计完美继承了Chromium内核的强大打印能力,同时融合了Node.js的硬件控制特性。

2. 实现基本打印功能

我们先用Electron官方API实现最基础的打印功能。以下示例基于Electron 28.x版本:

// 主进程代码
const { app, BrowserWindow } = require('electron')

function createWindow() {
  const mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: true
    }
  })

  // 加载含打印按钮的页面
  mainWindow.loadFile('index.html')
}

// HTML页面中的打印按钮点击处理
function onPrintClick() {
  // 获取当前窗口的webContents对象
  const win = remote.getCurrentWindow()
  
  // 调用打印API
  win.webContents.print({
    silent: false,          // 显示打印对话框
    printBackground: true,  // 打印CSS背景
    deviceName: ''          // 使用默认打印机
  }, (success) => {
    console.log(`打印${success ? '成功' : '失败'}`)
  })
}

这个基础实现包含了三个关键参数配置:

  • silent:控制是否显示系统打印对话框
  • printBackground:处理网页背景色的打印兼容
  • deviceName:指定特定打印设备(留空则使用默认)

3. 静默打印的实战应用

在无人值守的打印场景中,我们需要实现静默打印功能。修改主进程代码:

// 主进程代码(ipcMain处理)
ipcMain.on('silent-print', (event, htmlContent) => {
  const printWindow = new BrowserWindow({ show: false })
  
  printWindow.loadURL(`data:text/html,${encodeURIComponent(htmlContent)}`)
  
  printWindow.webContents.on('did-finish-load', () => {
    printWindow.webContents.print({
      silent: true,
      printBackground: true,
      deviceName: 'XP-58'  // 指定热敏打印机型号
    }, (success) => {
      printWindow.destroy()
      event.sender.send('print-result', success)
    })
  })
})

这里实现了两个重要功能:

  1. 隐藏窗口加载HTML内容
  2. 使用设备名称精准定位特定打印机 (注:实际设备名称可通过系统打印机列表获取)

4. 进阶打印机管理功能

整合printer模块实现硬件级控制(需先安装npm install printer):

const printer = require('printer')

// 获取打印机列表
function getPrinterList() {
  return printer.getPrinters().map(p => ({
    name: p.name,
    status: p.status,
    isDefault: p.isDefault
  }))
}

// 监控打印机状态变化
function monitorPrinter() {
  const timer = setInterval(() => {
    const devices = getPrinterList()
    if (!devices.some(d => d.name === '财务专用打印机')) {
      console.error('财务打印机离线!')
      clearInterval(timer)
    }
  }, 5000)
}

这个示例演示了三个核心能力:

  • 枚举本地打印设备
  • 识别默认打印机
  • 实时监控设备状态

5. 应用场景分析

物流面单打印系统需要:

  • 批量打印时自动跳过离线设备
  • 自适应不同尺寸面单纸
  • 打印失败自动重试机制

解决方案:

function bulkPrint(tasks) {
  tasks.forEach((task, index) => {
    const printer = getAvailablePrinter(task.size)
    
    printToDevice(task.content, printer).catch(err => {
      if (err.code === 'DEVICE_OFFLINE') {
        setTimeout(() => bulkPrint([task]), 30000)  // 30秒后重试
      }
    })
  })
}

6. 技术优缺点剖析

优势维度:

  • 排版精准:基于Chromium的打印预览引擎
  • 驱动免配置:依赖系统已安装的打印机驱动
  • CSS打印媒介支持:完美还原网页样式

待改进点:

  • 内存占用:每个打印窗口约消耗50MB内存
  • 字体依赖:需确保系统存在所需字体
  • 硬件交互局限:无法直接控制进纸器等物理设备

7. 注意事项与调试技巧

  1. DPI适配问题
@media print {
  /* 强制使用300DPI渲染 */
  body {
    width: 8.5in;
    height: 11in;
    margin: 0;
  }
}
  1. 打印超时陷阱
function safePrint(contents, options) {
  return new Promise((resolve, reject) => {
    const timeout = setTimeout(() => {
      reject(new Error('打印操作超时'))
    }, 30000)

    contents.print(options, (success) => {
      clearTimeout(timeout)
      success ? resolve() : reject()
    })
  })
}
  1. 跨平台差异处理策略
function getDefaultPrinter() {
  if (process.platform === 'win32') {
    return printer.getPrinters().find(p => p.isDefault)
  } else {
    // Mac系统需要特殊处理
    return execSync('lpstat -d').toString().split(':')[1].trim()
  }
}

8. 总结与展望

在实现Electron打印功能时,建议遵循分级策略:优先使用WebContents.print满足基础需求,再逐步引入打印机管理模块。未来可关注以下方向:

  • WebAssembly集成提升性能
  • 利用CUPS增强Linux支持
  • 与硬件厂商合作开发专属SDK