Skip to content

与nodejs进行通信

默认情况下,客户端的代码,是没法直接使用nodejs的api的,那么如果我们要使用这方面的能力应该怎么做呢?

第一种方法 进程间进行通信官方教程

大概的思路就是,使用preload.js,挂载一个公用的api比如这样

依赖的apiipcRenderer.sendipcMain.on

js
// preload.js
const { contextBridge, ipcRenderer } = require("electron");
contextBridge.exposeInMainWorld("electronAPI", {
  setTitle: (title) => ipcRenderer.send("setTitle", title),
});
1
2
3
4
5

main.js中进行接收,这是一个订阅者模式

js
const { app, BrowserWindow, ipcMain } = require("electron");
const path = require("path");
const createWindow = () => {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, "preload.js"),
    },
  });

  ipcMain.handle("ping", () => "ping");
  ipcMain.on("setTitle", (event, title) => {
    const webContents = event.sender;
    const win = BrowserWindow.fromWebContents(webContents);
    win.setTitle(title);
  });
  win.loadFile("index.html");
};

app.whenReady().then((res) => {
  createWindow();

  app.on("window-all-closed", () => {
    if (process.platform !== "darwin") app.quit();
  });
  app.on("activate", () => {
    if (BrowserWindow.getAllWindows().length === 0) createWindow();
  });
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

render.js中调用preload.js中暴露出来的api,从而实现交互:

js
// render.js
const button = document.querySelector("button");
const input = document.querySelector("#input");

const ping = async () => {
  const  value = input.value
  electronAPI.setTitle(value)
};
button.addEventListener("click", ping);
1
2
3
4
5
6
7
8
9

第二种方法,就是上面提到的方法【如何与nodejs进程同行通信】

这种方法依赖的api是 ipcRenderer.invokeipcMain.handle

第三种方案 主渲染器(Main to renderer)

主要依赖的是ipcRenderer.on,假如node层希望去通知客户端层,可以使用下面这种方法

  1. preload.js暴露出一个钩子,可以让客户端监听到
javascript
const { contextBridge, ipcRenderer } = require("electron");

contextBridge.exposeInMainWorld("electronAPI", {
  onUpdateCounter: (callback) => ipcRenderer.on('update-counter', callback)
});
1
2
3
4
5

WARNING

这里出于安全性的考虑,并没有将整个的ipcRenderer.on函数暴露了,而只是暴露出来一个key

  1. render.js中进行监听
javascript
window.electronAPI.onUpdateCounter((_event, value) => {
  const oldValue = Number(counter.innerText)
  const newValue = oldValue + value
  counter.innerText = newValue

  // 在这里我们可以使用event的这个参数,直接再次和node层进行交互
  _event.sender.send('counter-value', newValue)
})
1
2
3
4
5
6
7
8
  1. main.js中发送事件

这里模拟一个node希望和客户端交互的场景,我们创建出来两个菜单,并且发送事件,在win.webContents.send('update-counter', value) 发送的事件,会被客户端的回调函数中接收到,从而产生交互

javascript
const { app, BrowserWindow, ipcMain, dialog, Menu } = require("electron");
const path = require("path");
const createWindow = () => {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, "./src/preload.js"),
    },
  });
  const menu = Menu.buildFromTemplate([
    {
      label: app.name,
      submenu: [
        {
          click: () => win.webContents.send('update-counter', 1),
          label: 'count+1',
        },
        {
          click: () => win.webContents.send('update-counter', -1),
          label: 'count-1',
        }
      ]
    }

  ])
  Menu.setApplicationMenu(menu)

  win.loadFile("./index.html");

  win.webContents.openDevTools()
};
app.whenReady().then((res) => {

  ipcMain.on('counter-value', (_event, value) => {
    console.log(value) // 在这里监听,获得客户端返回的参数
  })

  createWindow();

  app.on("window-all-closed", () => {
    if (process.platform !== "darwin") app.quit();
  });
  app.on("activate", () => {
    if (BrowserWindow.getAllWindows().length === 0) createWindow();
  });
});


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49