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

如何在Electron中实现打印预览?替代系统默认打印对话框方案咨询

方案1:Electron原生能力实现(最推荐,完全解决样式/分页/字体问题)

该方案使用Chromium内核原生的PDF生成和打印能力,完全还原页面样式,不会出现前端转PDF工具的兼容问题:

步骤1:主进程配置IPC调用

在Cordova-electron的主进程中新增两个IPC监听事件,用于生成预览PDF和触发打印:

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

// 生成打印预览PDF
ipcMain.handle('generate-pdf-preview', async (event, printHTML, pageSize = 'A4') => {
  // 创建隐藏窗口渲染打印内容,保证样式和页面完全一致
  const printWin = new BrowserWindow({
    show: false,
    webPreferences: { webSecurity: false }
  })
  await printWin.loadURL(`data:text/html;charset=utf-8,${encodeURIComponent(printHTML)}`)
  // 调用原生PDF生成接口
  const pdfBuffer = await printWin.webContents.printToPDF({
    pageSize,
    printBackground: true,
    preferCSSPageSize: true,
    margins: { top: 10, bottom: 10, left: 10, right: 10 },
    pageBreaksAfter: '.page-break'
  })
  printWin.close()
  return pdfBuffer.toString('base64')
})

// 触发最终打印
ipcMain.handle('direct-print', async (event, printHTML, skipSystemDialog = true) => {
  const printWin = new BrowserWindow({ show: false })
  await printWin.loadURL(`data:text/html;charset=utf-8,${encodeURIComponent(printHTML)}`)
  const result = await printWin.webContents.print({
    silent: skipSystemDialog, // 设为true直接跳过系统打印对话框
    printBackground: true,
    pageSize: 'A4'
  })
  printWin.close()
  return result
})

步骤2:Preload脚本暴露API(开启上下文隔离时需要)

// preload.js
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
  generatePdfPreview: (html) => ipcRenderer.invoke('generate-pdf-preview', html),
  directPrint: (html, skipDialog) => ipcRenderer.invoke('direct-print', html, skipDialog)
})

步骤3:React端实现预览逻辑

// React组件代码
const [showPreview, setShowPreview] = useState(false)
const [previewPdfUrl, setPreviewPdfUrl] = useState('')
const [printHTML, setPrintHTML] = useState('')

const openPrintPreview = async () => {
  // 提取要打印的DOM和所有样式
  const printDom = componentRef.current.cloneNode(true)
  // 移除不需要打印的元素
  printDom.querySelectorAll('.hide-print').forEach(el => el.remove())
  // 整合所有页面样式,保证渲染一致
  const allStyles = Array.from(document.styleSheets).map(sheet => {
    try { return Array.from(sheet.cssRules).map(r => r.cssText).join('') }
    catch { return '' }
  }).join('')
  // 组装完整打印HTML
  const fullHTML = `
    <!DOCTYPE html>
    <html>
      <head>
        <style>${allStyles}</style>
        <style>
          @media print { .page-break { page-break-after: always; } }
        </style>
      </head>
      <body>${printDom.outerHTML}</body>
    </html>
  `
  setPrintHTML(fullHTML)
  // 调用主进程生成PDF
  const pdfBase64 = await window.electronAPI.generatePdfPreview(fullHTML)
  const blob = new Blob([Uint8Array.from(atob(pdfBase64), c => c.charCodeAt(0))], { type: 'application/pdf' })
  setPreviewPdfUrl(URL.createObjectURL(blob))
  setShowPreview(true)
}

// 确认打印
const confirmPrint = async () => {
  await window.electronAPI.directPrint(printHTML, true)
  setShowPreview(false)
}

你可以自己开发React模态框组件渲染预览PDF(可嵌入PDF.js实现自定义预览UI),完全替代系统默认打印对话框。


方案2:优化现有html2pdf.js配置(无需修改主进程)

如果不想调整主进程代码,可优化现有配置解决大部分兼容问题:

const opt = {
  margin: 10,
  filename: 'myfile.pdf',
  image: { type: 'png', quality: 1 }, // 用png避免压缩失真
  html2canvas: { 
    scale: 3, // 调高分辨率解决字体模糊问题
    logging: true, 
    width: 794, // A4标准像素宽度
    useCORS: true,
    allowTaint: true,
    letterRendering: true
  },
  jsPDF: { unit: 'mm', orientation: 'portrait', format: 'a4' },
  pagebreak: { 
    mode: ['css', 'legacy'], // 优先识别CSS分页规则
    after: '.page-break' 
  }
}

同时给需要打印的每个页面节点设置固定高度height: 297mm(A4高度),配合overflow: hidden避免分页错乱。


内容的提问来源于stack exchange,提问作者Nishil S.B

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 10:30:03