文章目录


前言

在开发过程中难免会遇到许多文档的输出,本文主要讲使用electron导出pdf的功能,原理就是将html代码转换为pdf文件:先使用showOpenDialogSync获取到保存文件的路径,获取到html(html样式尽量使用行内样式,不然容易出bug)后将文件路径和html通过electron的ipcRenderer.send发送到主进程,主进程接受到子进程发送的数据之后使用printToPDF将html代码转换为pdf文件,最后使用fs.writeFile将文件保存。

一、子进程

1.引入remote和ipcRenderer两个模块。

 这个需要根据自己的项目引入具体的模块,作者已经引入

2.获取html代码

代码如下:

  // 获取报告的html代码

  getExportReportHtml(): string {

    return `

    <!DOCTYPE html>

    <html>

      <head>

        <meta charset="UTF-8">

        <meta name="viewport" content="width=device-width, initial-scale=1.0">

        <meta name="author" content="CEditor">

        <title>导出报告</title>

      </head>

      <body class="markdown-body code-github">

        <h1>41312</h1>

      </body>

    </html>

    `;

  }


3.获取文件下载路径

代码如下:

     let filePath = this.es.remote.dialog.showOpenDialogSync({

        title: "导出报告",

        buttonLabel: "导出报告",

        properties: ["openDirectory"], //openDirectory选择文件夹

      });

4.将html和文件下载路径发送到主进程

ipcRenderer的第一个参数做序列化处理,内容什么都可以,代码如下:

    this.es.ipcRenderer.send(

      "export-pdf",

      (<string>"4a3s2f", { filePath, html, mode })

    );

5.监听主进程反馈的信息

代码如下:

    this.es.ipcRenderer.once("export-pdf-res", (_e, data) => {

      console.log("结果:", data);

      if (!data.success) {

        this.message.error(data.msg);

      }

    });

二、主进程

1.显示pdf(预览)

参数比较多,解释都放在代码中注释了,代码如下:

    let pdfWindow:any = new BrowserWindow({

      webPreferences: {

        nodeIntegration: true,//是否启用Node integration

        webSecurity: false,//当设置为 false, 它将禁用同源策略

        enableRemoteModule: true

      },

      show: obj.mode==1?true:false, // 是否显示窗口

      width: 1000,

      height: 800,

      fullscreenable: true,//决定最大化/缩放窗口按钮是切换全屏模式还是最大化窗口

      minimizable: false,//设置用户是否可以手动将窗口最小化。 在Linux上不起作用

      modal:true,//是否为模态框

      center:true,//是否居中显示

      icon:'./src/assets/icons/icon.ico',//窗口的图标

      // icon:'.\\icon.ico',

    });

    pdfWindow.loadURL(`data:text/html;charset=utf-8,${encodeURI(obj.html)}`);

2.下载pdf(预览)

下载pdf并通知子进程是否下载成功,代码如下:

      pdfWindow.webContents.on('did-finish-load', () => {

        // Use default printing options

        const pdfPath = obj.filePath;

        pdfWindow.webContents.printToPDF({

          printBackground: true

        }).then(data => {

          fs.writeFile(pdfPath, data, error => {

            if (error) throw error;

            win.webContents.send('export-pdf-res', { success: true,msg:`导出成功,路径:${pdfPath}` });

            pdfWindow.close();// 保存pdf过后关闭该窗口

            pdfWindow = null;

          });

        }).catch(error => {

          win.webContents.send('export-pdf-res', { success:false,msg: `导出失败,路径:${JSON.stringify(error)}` });

        });

      });

三、完整代码

1.子进程:

// 导出报告

  /**

   * @params mode 1:预览,2:导出

   */

  exportReport(mode = 1) {

    if (!this.es.remote) return;

    let res = undefined;

    let filePath = undefined;

    if (mode == 2) {

      res = this.es.remote.dialog.showOpenDialogSync({

        title: "导出报告",

        buttonLabel: "导出报告",

        properties: ["openDirectory"], //openDirectory选择文件夹

      });

      if (!res) return;

      let fileName = "报告" ;

      filePath = this.es.path.join(res[0], `${fileName}.pdf`);

    }

    let html = this.getExportReportHtml();

    this.es.ipcRenderer.send(

      "export-pdf",

      (<string>"4a3s2f", { filePath, html, mode })

    );

    this.es.ipcRenderer.once("export-pdf-res", (_e, data) => {

      console.log("结果:", data);

      if (!data.success) {

        this.message.error(data.msg);

      }

    });

    console.log(res);

  }

  // 获取报告的html代码

  getExportReportHtml(): string {

    return `

    <!DOCTYPE html>

    <html>

      <head>

        <meta charset="UTF-8">

        <meta name="viewport" content="width=device-width, initial-scale=1.0">

        <meta name="author" content="CEditor">

        <title>导出报告</title>

      </head>

      <body class="markdown-body code-github">

        <h1>41312</h1>

      </body>

    </html>

    `;

  }

2.主进程:

 

  ipcMain.on('export-pdf',async (_event,obj)=>{

    let pdfWindow:any = new BrowserWindow({

      webPreferences: {

        nodeIntegration: true,//是否启用Node integration

        webSecurity: false,//当设置为 false, 它将禁用同源策略

        enableRemoteModule: true

      },

      show: obj.mode==1?true:false, // 是否显示窗口

      width: 1000,

      height: 800,

      fullscreenable: true,//决定最大化/缩放窗口按钮是切换全屏模式还是最大化窗口

      minimizable: false,//设置用户是否可以手动将窗口最小化。 在Linux上不起作用

      modal:true,//是否为模态框

      center:true,//是否居中显示

      icon:'./src/assets/icons/icon.ico',//窗口的图标

      // icon:'.\\icon.ico',

    });

    pdfWindow.loadURL(`data:text/html;charset=utf-8,${encodeURI(obj.html)}`);

    if(obj.mode==2){

      pdfWindow.webContents.on('did-finish-load', () => {

        // Use default printing options

        const pdfPath = obj.filePath;

        pdfWindow.webContents.printToPDF({

          printBackground: true

        }).then(data => {

          fs.writeFile(pdfPath, data, error => {

            if (error) throw error;

            win.webContents.send('export-pdf-res', { success: true,msg:`导出成功,路径:${pdfPath}` });

            pdfWindow.close();// 保存pdf过后关闭该窗口

            pdfWindow = null;

          });

        }).catch(error => {

          win.webContents.send('export-pdf-res', { success:false,msg: `导出失败,路径:${JSON.stringify(error)}` });

        });

      });

    }

  })

总结

有什么疑问的地方欢迎评论,我会不定期进行回复。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐