Electron的主进程和渲染进程以及进程通信

1.主进程

核心:使用BrowserWindow来创建和管理窗口。

每个Electron应用都有且仅有一个主进程,它主要在Node.js环境当中运行,具有require模块和使用所有Node.js API(如__dirname、fs、process等)的能力,无法访问window或alert等这些非Node.js的API。

主进程通过 app 模块控制应用的生命周期,并通过 BrowserWindow 创建窗口。例如:

const { app, BrowserWindow } = require('electron');

app.whenReady().then(() => {
  const win = new BrowserWindow({ width: 800, height: 600 });
  win.loadFile('index.html');
});
 

2.渲染进程

核心:将HTML、CSS和JavaScript转换为可交互的网页(包括解析HTML、构建DOM树、样式计算、子资源加载等‌ );‌

每个BrowserWindow实例都对应一个单独的渲染器进程,主要运行在 Chromium 环境中,它可以访问window、alert等API,但无法使用任何Node.js的API,也不具有require模块的能力。

一个主进程可同时管理多个渲染进程。

默认情况下,渲染进程无法调用任何Node.js的API,但如果需要,可以通过预加载脚本来安全地访问Node.js的部分API(像__dirname、fs就无法被访问)。

 3.预加载脚本(preload)

作用:Node.js和Web API之间的桥梁,它可以安全地将部分Node.js API暴露给网页。

实现:主进程在 new BrowserWindow 内增加属性 webPreferences ,并用绝对路径引入preload.js文件,preload.js文件中通过 electron 的 contextBridge.exposeInMainWorld 将部分API安全地暴露给渲染进程,在渲染进程中的window即可访问到这些被暴露的API。

完整代码:

main.js

const { app, BrowserWindow } = require('electron');
const path = require('path');

function createWindow() {
    const win = new BrowserWindow({
        width: 800,  // 窗口宽度
        height: 600,  // 窗口高度
        autoHideMenuBar: true, // 隐藏默认的菜单栏
        // x: 0,  // 窗口在横坐标上的位置
        // y: 0,  // 窗口在纵坐标上的位置
        // alwaysOnTop: true,  // 窗口置顶
        webPreferences: {
            preload: path.resolve(__dirname, './preload.js')  // 必须写绝对路径
        }  // web高级配置
    });
    win.loadFile('./pages/index.html')
}

app.on('ready', () => {
    console.log('启动了应用!')
    createWindow();
    // (macOS专用)当应用被激活时,判断当前是否有窗口,若没有,则创建窗口
    app.on('activate', () => {
        if (BrowserWindow.getAllWindows().length === 0) createWindow()
    })
});

// 当所有窗口关闭,并且当前不是macOS系统时,退出应用
app.on('window-all-closed', () => {
    if (process.platform !== 'darwin') app.quit()
});
preload.js

console.log('preload', process.version);
const { contextBridge } = require('electron');

contextBridge.exposeInMainWorld('myAPI', {
    version: process.version
});  // 接收两个参数,第一个参数是key,render.js中用该key值访问,第二个参数则是值
render.js

const btn1 = document.getElementById('btn1');

btn1.onclick = () => {
    console.log('version', myAPI.version);
}
index.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>index</title>
        <link rel="stylesheet" href="./index.css">
        <meta http-equiv="Content-Security-Policy" content="default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:;"/>
    </head>
    <body>
        <h1>Electron开发</h1>
        <button id="btn1">点我一下</button>
        <script type="text/javascript" src="./render.js" ></script>
    </body>
</html>

 如此即可完成点击按钮【点我一下】就输出node版本这一小功能。

预加载脚本运行在渲染进程当中,但在网页内容加载之前执行,它比普通渲染器代码有更高的权限,可以访问Node.js的API,同时又可以与网页内容进行安全的交互。

若现有主进程(main.js)、预加载脚本(preload.js)、渲染进程(render.js)三个脚本,且三个脚本中各有一个console输出,则正确的输出顺序是main.js —> preload.js —> render.js,其中,preload.js和render.js的console输出都在BrowserWindow窗口的控制台中。

4.进程通信(IPC)

IPC:InterProcess Communication,是UI调用原生API的唯一方法。

为什么需要IPC?

预加载脚本无法使用__dirname、fs等Node.js API,当渲染进程需要用到这些API时,只能通过IPC来通知主进程调用这些模块来干活。

4.1 渲染进程 —>主进程(单向)

预加载脚本:ipcRenderer.send('信道', 参数) 发送;

主进程:ipc.on('信道', 回调) 接收;

4.2 渲染进程 <—>主进程(双向)

预加载脚本:ipcRenderer.invoke('信道', 参数)  调用(invoke的返回值是一个promise实例);

主进程:ipc.handle('信道', 回调)  处理;

4.3 主进程 —>渲染进程(单向)

主进程:win.webContents.send('信道', 数据) 发送;

预加载脚本:ipcRenderer.on('信道', 回调) 接收并调用回调函数;

4.4 渲染进程 <—>渲染进程

渲染进程与渲染进程之间无法直接进行通信,可以将主进程作为渲染器之间的消息代理(中介)。 这需要将消息从一个渲染器发送到主进程,然后主进程将消息转发到另一个渲染器。

例:实现将窗口1中input的值复制到窗口2中展示的小功能

最终结果展示:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值