如何在Electron JS + Vue项目中实现PDF(如发票)的创建与保存功能
Electron + Vue 生成发票PDF 可行方案及避坑指南
你之前试用的第三方PDF库大多是面向纯Node.js环境设计的,在Electron环境下容易出现原生模块ABI不兼容、沙箱权限限制等报错问题,用Electron官方自带的webContents.printToPDF()是最稳妥的方案,完全可以满足发票类PDF的格式定制需求。
优先推荐:使用Electron原生API实现(无额外依赖、适配性最高)
实现步骤
- 首先在Vue项目中单独开发发票模板页面,把发票的样式、排版用HTML+CSS写好,支持动态填充用户、金额等发票数据,也可以用CSS的
page-break-after: always属性控制分页位置,避免内容被截断。 - 渲染进程通过IPC通信向主进程发送生成PDF的请求,传递发票的动态数据。
渲染进程示例代码:// 渲染进程(Vue页面)发送请求 const generatePdf = async (invoiceData) => { const savePath = await window.ipcRenderer.invoke('generate-invoice-pdf', invoiceData) console.log('PDF已保存至:', savePath) } - 主进程接收请求后,新开隐藏窗口加载填好数据的发票模板页面,调用原生API生成PDF后保存到本地。
主进程示例代码:const { ipcMain, BrowserWindow, dialog } = require('electron') const fs = require('fs/promises') ipcMain.handle('generate-invoice-pdf', async (event, invoiceData) => { // 新建隐藏窗口用于渲染发票内容 const printWin = new BrowserWindow({ show: false, webPreferences: { contextIsolation: true, nodeIntegration: false } }) // 加载发票模板页面,开发环境用localhost地址,打包后用本地app协议路径 const templateUrl = process.env.NODE_ENV === 'development' ? `http://localhost:5173/invoice?data=${encodeURIComponent(JSON.stringify(invoiceData))}` : `app://./invoice.html?data=${encodeURIComponent(JSON.stringify(invoiceData))}` await printWin.loadURL(templateUrl) // 生成PDF配置,可自定义纸张大小、边距、是否打印背景等 const pdfBuffer = await printWin.webContents.printToPDF({ pageSize: 'A4', margins: { top: 1.5, bottom: 1, left: 0.8, right: 0.8 }, printBackground: true, // 必须开启,否则自定义背景色、边框样式会丢失 headerFooter: { pageNumber: true // 可自定义页眉页脚,比如加发票编号等 } }) // 弹出保存对话框让用户选择存储路径 const { filePath, canceled } = await dialog.showSaveDialog({ defaultPath: `发票_${Date.now()}.pdf`, filters: [{ name: 'PDF文件', extensions: ['pdf'] }] }) if (!canceled && filePath) { await fs.writeFile(filePath, pdfBuffer) } printWin.destroy() return filePath })
第三方库报错解决方法
如果你坚持要使用PdfKit、pdf-creator-node这类第三方库,需要处理Electron和纯Node环境的兼容性问题:
- 所有第三方PDF库的调用逻辑都放在主进程执行,不要在渲染进程调用,避免沙箱权限限制。
- 安装依赖后执行
electron-rebuild命令,重建适配当前Electron版本的原生模块,解决ABI不一致导致的加载报错。 - 在electron-builder的配置文件中,把用到的PDF依赖添加到
externals列表中,打包时会单独处理原生模块,避免打包后丢失依赖。
通用避坑点
- 发票样式调试时可以先把隐藏窗口的
show属性设为true,确认页面渲染正常后再改成隐藏。 - 打包时要确保发票模板页面被正确打包到应用资源目录中,不要使用开发环境的本地服务器地址,否则打包后页面无法加载。
- 不要为了适配第三方库随意开启
nodeIntegration、关闭contextIsolation,会带来严重的安全风险。
内容的提问来源于stack exchange,提问作者Yanis02015
相关产品推荐
相关产品推荐

