如何在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
相关产品推荐
相关产品推荐

