Electron 项目实战 01:主进程与渲染进程通信

项目搭建

  1. 创建命令

    bash 复制代码
    mkdir electron_app
    cd electron_app
    npm init -y
    yarn add electron -D
  2. 必要的配置

    • package.json

      bash 复制代码
      {
        "name": "my-electron-app",
        "version": "1.0.0",
        "main": "main.js",
        "license": "MIT",
        "scripts": {
          "dev": "electron ."
        },
        "devDependencies": {
          "electron": "^28.0.0"
        }
      }
      • main:设置入口文件
      • scripts: 添加开发命令
    • main.js

      jsx 复制代码
      const { app, BrowserWindow } = require("electron");
      
      const createWindow = () => {
      	const win = new BrowserWindow({
      		width: 800,
      		height: 600,
      	});
      	
      	// 添加首页面
      	win.loadFile("index.html");
      };
      
      //! 1. app已准备就绪
      app.whenReady().then(() => {
      	//2. 创建一个win窗口
      	createWindow();
      	console.log(process.platform);
      	
        //3. 添加预防处理,如果app已处于active状态还没window自动创建一个
      	app.on("activate", () => {
      		if (BrowserWindow.getAllWindows().length === 0) {
      			createWindow();
      		}
      	});
      });
      
      app.on("window-all-closed", () => {
      	// 说明:不为mac os 平台,添加此退出命令
      	if (process.platform !== "darwin") {
      		console.log("quit");
      		app.quit();
      	}
      });
  • index.html

    jsx 复制代码
    <!DOCTYPE html>
    <html>
    
    <head>
    	<meta charset="UTF-8" />
    	<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
    	<meta http-equiv="Content-Security-Policy"
    				content="default-src 'self'; script-src 'self'" />
    	<meta http-equiv="X-Content-Security-Policy"
    				content="default-src 'self'; script-src 'self'" />
    	<title>Hello from Electron renderer!</title>
    </head>
    
    <body>
    	<h1>Hello from Electron renderer!</h1>
    	<p>👋</p>
    </body>
    
    </html>
  • yarn dev 看下效果

说明最简单的项目已搭建好,我们来看下Render process 与 Main process 是如何通讯的

主进程与渲染进程通讯

  • 为了让代码更加清晰,我们将渲染进程的代码写到renderer.js中
  • 由于Electron是一个Node环境,可以完全的访问系统,为了安全我们添加一个preload 脚本来建立一个桥,让渲染进程与主进程进行通信
  • 利用Electron包中的ipcMain 和 ipcRenderer 进行通信

具体代码:

  • main.js

    jsx 复制代码
    const { app, BrowserWindow, ipcMain } = require("electron");
    const path = require("node:path");
    
    const createWindow = () => {
    	const win = new BrowserWindow({
    		width: 800,
    		height: 600,
    		webPreferences: {
    			//! 3.注意这里添加了预加载preload.js
    			preload: path.join(__dirname, "preload.js"),
    		},
    	});
    
    	win.loadFile("index.html");
    };
    
    app.whenReady().then(() => {
    	//! 主进程,处理渲染进程的消息
    	ipcMain.handle("ping", () => {
    		return `I'm ipcMain`;
    	});
    
    	// ! 1.主进程监听来自渲染进程的消息
    	ipcMain.on("message-from-renderer", (event, arg) => {
    		console.log("Renderer Process Message:", arg);
    
    		//! 2.发送回复消息到渲染进程
    		event.sender.send("message-from-main", "Hello from main process!");
    	});
    
    	createWindow();
    	console.log(process.platform);
    	app.on("activate", () => {
    		if (BrowserWindow.getAllWindows().length === 0) {
    			createWindow();
    		}
    	});
    });
    
    app.on("window-all-closed", () => {
    	if (process.platform !== "darwin") {
    		console.log("quit");
    		app.quit();
    	}
    });
  • preload.js

    jsx 复制代码
    const { contextBridge, ipcRenderer } = require("electron");
    
    contextBridge.exposeInMainWorld("versions", {
    	node: () => process.versions.node,
    	chrome: () => process.versions.chrome,
    	electron: () => process.versions.electron,
    	//! 给桥上线添加对应方法
    	ping: (name) => ipcRenderer.invoke("ping", name),
    });
    
    //! 1.添加渲染进程与主进程的桥梁接口
    contextBridge.exposeInMainWorld("electronAPI", {
    	sendMessageToMain: (message) => {
    		ipcRenderer.send("message-from-renderer", message);
    	},
    	receiveMessageFromMain: (callback) => {
    		ipcRenderer.on("message-from-main", (event, message) => {
    			callback(message);
    		});
    	},
    });
  • renderer.js

    jsx 复制代码
    const information = document.getElementById("info");
    information.innerText = `This app is using Chrome (v${versions.chrome()}), Node.js (v${versions.node()}), and Electron (v${versions.electron()})`;
    
    const func = async () => {
    	//! 渲染进程, 调用主进程方法
    	const response = await window.versions.ping();
    	console.log("渲染进程接收主进程的消息:", response); // prints out 'pong'
    };
    
    func();
    
    //! 1.渲染进程往主进程发送消息
    window.electronAPI.sendMessageToMain("Hello from the renderer process!");
    //! 2.渲染进程接收到主进程的消息
    window.electronAPI.receiveMessageFromMain((message) => {
    	console.log(`Received message from main process: ${message}`);
    });

yarn dev 看下效果

  • 主进程收到渲染进程消息(注意:主进程接收到的消息打印在终端控制台)
  • 渲染进程收到主进程消息

说明:可能你不知道打开Electron App的日志控制台,看下图:

总结

  • 整体来说参看官方文档和网上的文章就可以轻松实现

参考文献

更多

家人们,我最近花了2个多月开源了一个文章发布助手artipub,可以帮你一键将markdown发布至多平台(发布和更新),方便大家更好的传播知识和分享你的经验。

目前已支持平台:个人博客、Medium、Dev.to(未来会支持更多平台)

官网地址:https://artipub.github.io/artipub/

仓库地址:https://github.com/artipub/artipub

目前库已可以正常使用,欢迎大家体验、如果你有任何问题和建议都可以提Issue给我反馈。

如果你感兴趣,特别欢迎你的加入,让我们一起完善好这个工具。

帮忙点个star⭐,让更多人知道这个工具,感谢大家🙏

相关推荐
D_J_Dragon23 分钟前
快速搭建最简单的前端项目vue+View UI Plus
前端·vue.js·view design
软件技术NINI23 分钟前
如何使用 Vue 3 的 Composition API
前端·javascript·vue.js
猿究院+24 分钟前
Vue3中的监听器。toRefs与toRef的区别
前端·javascript·vue.js
LJPchosen125 分钟前
el-tree组件进来的时候默认展开并且滚动定位到展开项的位置
前端·javascript·vue.js
向上的时钟塔1 小时前
Vue3 el-switch @change事件在初始化时会自动调用问题
前端·javascript·vue.js
好哈优学编程1 小时前
JavaScript知识点3
开发语言·前端·javascript
软件技术NINI1 小时前
JavaScript网页设计案例
javascript
程序者王大川2 小时前
【前端】Flutter vs uni-app:性能对比分析
前端·flutter·uni-app·安卓·全栈·性能分析·原生
Fan_web2 小时前
JavaScript高级——作用域和作用链
开发语言·前端·javascript·css·html
我码玄黄2 小时前
解锁定位服务:Flutter应用中的高德地图定位
前端·flutter·dart