Electron V28主进程与渲染进程互相通信总结

本文示例采用Electron+Vue3+TS编写,请读者理顺思路,自行带入自己的项目。
注: 读本文前请先搞懂什么是主进程,什么是渲染进程。

在Electron中有着ipcMainipcRenderer、contextBridge模块,以及创建窗口对象上的webContents。很显然ipcMain和窗口对象上的webContents是在主进程中使用的,ipcRenderer和contextBridge(用于向渲染进程暴露API)是在预加载脚本中使用的。
请看下方示例,关键讲解写在代码注释中。

一、主进程发送消息到渲染进程

主进程中发送消息,是使用new 窗口时的对象上的webContents发送消息。例如:
main.js中

let appWindow;
const createWindow = () => {appWindow = new BrowserWindow({width: 850,height: 700,webPreferences: {preload: path.join(path.resolve(), 'preload/index.js')}})// 创建窗口后,向渲染进程发送平台信息,但是不能直接发送给渲染进程,需要通过预加载脚本进行中转appWindow.webContents.send('platform', process.platform)
}

于是在preload/index.js中:

const { contextBridge, ipcRenderer } = require('electron')
// ipcRenderer监听消息名为platform的事件,并在第二个参数回调函数中接收参数
// 回调函数又包含两个参数,一个是事件信息,一个是消息传递的参数
ipcRenderer.on('platform', (_, arg) => {// 拿到参数后,我们使用contextBridge向渲染进程中(也就是html或vue界面)暴露名为platform的API,当然名字可自定义其它。// 暴露出的API挂载在window对象上contextBridge.exposeInMainWorld('platform', arg)
})

于是在vue界面中,我们可以使用以下代码获取平台信息;
index.vue文件

<script setup lang="ts">import { ref, onMounted } from 'vue'const platform = ref<string>('')onMounted(() => {// 此时可以在window对象上直接读取platform数据值platform.value = window.platform})
</script>

二、主进程发送消息,渲染进程进行监听

上面一个示例只有在窗口创建时向渲染进程发送了一个消息,且只发送一次。那假如我现在有个需求是需要监听窗口的变化:最大化、最小化、缩小等等信息。获取窗口最大小的API存在于创建的窗口对象上,那么此时就应该在主进程中监听窗口变化发送消息给渲染进程,并且渲染进程需要监听主进程发送的消息。
主进程 main.js

let appWindow;
const createWindow = () => {appWindow = new BrowserWindow({width: 850,height: 700,webPreferences: {preload: path.join(path.resolve(), 'preload/index.js')}})// appWindow对象上的on方法监听窗口事件appWindow.on('resize', () => {// 当窗口发生变化时,使用webContents.send方法向预加载脚本发送消息,消息名为resizeWindow,并挈带参数为窗口是否最大化appWindow.webContents.send('resizeWindow', appWindow.isMaximized())})
}

那么在预加载脚本中preload/index.js就有了如下代码:

const { contextBridge, ipcRenderer } = require('electron')// 首先向渲染进程中暴露出一个名为resizeWindow的API(名字可自定义),并将此API以对象的形式向外暴露,对象中编写一个监听窗口更新的方法,名为onUpdateWindow
// 此更新方法接收一个回调函数,用于在渲染进程中获取参数
// 此用法成为 高阶函数
// 更新方法的方法体为 ipcRenderer监听主进程发送的resizeWindow事件
// 在接受窗口变化事件的第二个参数中接收变化参数并调用callback()函数,将变化值传递进此回调中
contextBridge.exposeInMainWorld('resizeWindow', {onUpdateWindow: (callback) => ipcRenderer.on('resizeWindow', (_, value) => callback(value)),
})

在渲染进程中:

<script setup lang="ts">
import { ref, onMounted } from 'vue'const isMaxWin = ref<boolean>(false)onMounted(() => {// 调用window对象上的resizeWindow中的onUpdateWindow,并传递一个函数进去,//此函数对应的就是上方的callback,当ipcRenderer监听到事件后调用callback(),// 此回调函数就能够接收到窗口是否最大化的值window.resizeWindow.onUpdateWindow((value: boolean) => {isMaxWin.value = value})
})
</script>

三、渲染进程发送消息到主进程

渲染进程向主进程发送消息也是预加载脚本中向渲染进程暴露出一个API,渲染进程中调用此API,触发预加载脚本中对应的函数,此函数可以通过ipcRenderer调用主进程中的方法。

首先预加载脚本中的代码:

const { contextBridge, ipcRenderer } = require('electron')// 向渲染进程的window对象中绑定languageAPI,此API以对象的形式存在一个setTitle方法
// 此方法接收一个title并在方法体中使用ipcRenderer.invoke调用主进程中名为language:setTitle的监听事件
// 注意:language:setTitle只是自定义的名称,为了更醒目而已,开发者可以自定义其他名称
contextBridge.exposeInMainWorld('language', {setTitle: (title) => ipcRenderer.invoke('language:setTitle', title),
})

主进程中的代码:

const { BrowserWindow, ipcMain} = require('electron');let appWindow;
const createWindow = () => {appWindow = new BrowserWindow({width: 850,height: 700,webPreferences: {preload: path.join(path.resolve(), 'preload/index.js')}})
}
// 预加载脚本中invoke对象的监听事件为ipcMain.handle
// 所以此时主进程会监听名为language:setTitle的事件,并在回调函数中的第二个参数接收参数。
ipcMain.handle('language:setTitle', (_, title) => {// 设置窗口名称appWindow.setTitle(title)
})

在渲染进程中调用预加载脚本中定义的方法:

<script setup lang="ts">
import { ref } from 'vue'
import { useI18n } from 'vue-i18n'const { locale, t } = useI18n()
const changeLanguage = (language: string) => {locale.value = language// 当在界面中触发此方法时 调用window.language.setTitle方法并传入参数window.language.setTitle(t('app.name'))
}
</script>

四、解决预加载脚本暴露在window对象上的数据在ts中报错问题

由于自定义的API名称挂载到了window对象上,window此前并无此API,所以在ts的代码编写中会出现Proerty does not exist on type 'Window & typeof globalThis'的错误,即使代码可以运行。
所以此时我们需要定义.d.ts文件声明Window的API类型。
在项目根目录或者适合你项目的地方创建任意名称的.d.ts文件,并编写文件内容:

declare module '*.vue';type handleWindowAPI = {get: () => Promise<boolean>;set: (value: string) => Promise<void>;
}
type languageAPI = {setTitle: (title: string) => void;
}
type darkModeAPI = {toggle: () => Promise<boolean>;
}
type resizeWindowAPI = {onUpdateWindow: (callback: Function) => Promise<boolean>;
}
interface Window {platform: string;language: languageAPI;darkMode: darkModeAPI;handleWindow: handleWindowAPI;resizeWindow: resizeWindowAPI;
}

之后在tsconfig.json文件中的include属性中加载此ts文件:

{"compilerOptions": {"target": "ES2020","useDefineForClassFields": true,"module": "ESNext","lib": ["ES2020", "DOM", "DOM.Iterable"],"skipLibCheck": true,/* Bundler mode */"moduleResolution": "bundler","allowImportingTsExtensions": true,"resolveJsonModule": true,"isolatedModules": true,"noEmit": true,"jsx": "preserve",/* Linting */"strict": true,"noUnusedLocals": true,"noUnusedParameters": true,"noFallthroughCasesInSwitch": true},// 这里加载项目所有src下以ts结尾的文件"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"],"references": [{ "path": "./tsconfig.node.json" }]
}

最后提醒!!!

在预加载脚本中向渲染进程中暴露API时,暴露同一个名称的API的代码只能执行一次,否则将会报错:Cannot bind an API on top of an existing property on the window object

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/230255.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

-bash: docker-compose: 未找到命令

-bash: docker-compose: 未找到命令 我在使用Docker搭建Nacos容器时遇到了这个问题&#xff1a;是没有安装 docker-compose工具 。 docker-compose的用处主要体现在以下几个方面&#xff1a; 快速搭建开发环境&#xff1a;使用docker-compose可以快速搭建起开发环境&#xff0…

一分钟轻松制作AI数字人播报视频

随着人工智能的快速发展&#xff0c;AI数字人播报成为了媒体和信息传播领域的一项创新技术。AI数字人播报是利用人工智能技术创建的一系列短视频&#xff0c;以新闻主播为中心&#xff0c;展示各种场景和情境能够以短视频的形式进行新闻的报道。这种创新的内容形式在社交媒体和…

Java刷题篇——单链表练习题上

206. 反转链表 - 力扣&#xff08;LeetCode&#xff09; 1. 题目描述 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例1 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1] 示例2 输入&#xff1a;head [1,2] 输出&…

<软考高项备考>《论文专题 - 14 绩效域(四)》

8 交付绩效域 交付绩效域涉及与交付项目相关的活动和职能。在项目整个生命周期过程中&#xff0c; 有效执行本绩效域可以实现预期目标&#xff0c;主要包含&#xff1a; ①项目有助于实现业务目标和战略&#xff1b; ②项目实现了预期成果&#xff1b; ③在预定时间内实现了项…

Spring Boot 3 + Vue 3 整合 WebSocket (STOMP协议) 实现广播和点对点实时消息

&#x1f680; 作者主页&#xff1a; 有来技术 &#x1f525; 开源项目&#xff1a; youlai-mall &#x1f343; vue3-element-admin &#x1f343; youlai-boot &#x1f33a; 仓库主页&#xff1a; Gitee &#x1f4ab; Github &#x1f4ab; GitCode &#x1f496; 欢迎点赞…

PostgreSQL基础

一、数据库操作命令 创建数据库 CREATE DATABASE xxxxxxx; 删除数据库 drop databse xxxxx; 查看所有数据库 \l 切换数据库 \c xxx 二、模式的更改 a)重命名&#xff1a;alter schema 旧名字 to 新名字; b)修改模式的归属用户&#xff1a;alter schema 模式名 to 新用户; 模式…

CDH安装出现Cannot open channel to X at election address Connection refused

CDH安装出现Cannot open channel to X at election address Connection refused 在刚刚启动cdh的时候要是出现以上的问题或者 org.apache.zookeeper.server.quorum.QuorumCnxManager: Cannot open channel to 3 at election address srv252/10.1.50.252:4181 java.net.Connec…

06组团队项目-Beta冲刺-2/3

github仓库&#xff1a;https://github.com/orgs/oucdehaze/repositories 冲刺概况汇报 前端 上周冲刺中完成的任务及遇到的问题 这一周我们小组中负责前端部分的同学继续完善了web网页的界面。在上一周的基础上对字体颜色和字体内容进行了修改&#xff0c;使得网站的专业性…

高可用接入层技术演化及集群概述

集群概述 集群的介绍及优势 集群&#xff1a;将多台服务器通过硬件或软件的方式组合起来&#xff0c;完成特定的任务&#xff0c;而这些服务器对外表现为一个整体。集群的优势 高可靠性&#xff1a;利用集群管理软件&#xff0c;当主服务器故障时&#xff0c;备份服务器能够自…

2023年国赛高教杯数学建模D题圈养湖羊的空间利用率解题全过程文档及程序

2023年国赛高教杯数学建模 D题 圈养湖羊的空间利用率 原题再现 规模化的圈养养殖场通常根据牲畜的性别和生长阶段分群饲养&#xff0c;适应不同种类、不同阶段的牲畜对空间的不同要求&#xff0c;以保障牲畜安全和健康&#xff1b;与此同时&#xff0c;也要尽量减少空间闲置所…

【SpringBoot实战】实现用户名密码登录

【SpringBoot实战】实现用户名密码登录 在Java项目中&#xff0c;实现用户名密码登录是最基本的功能。尽管实现起来不难&#xff0c;但也有些细节问题&#xff0c;故写下此篇博客作为记录。 1.创建用户表 CREATE TABLE ad_user (id int unsigned NOT NULL COMMENT 主键,name…

代码随想录算法训练营第五十五天 _ 动态规划_392. 判断子序列、115.不同的子序列。

学习目标&#xff1a; 动态规划五部曲&#xff1a; ① 确定dp[i]的含义 ② 求递推公式 ③ dp数组如何初始化 ④ 确定遍历顺序 ⑤ 打印递归数组 ---- 调试 引用自代码随想录&#xff01; 60天训练营打卡计划&#xff01; 学习内容&#xff1a; 392. 判断子序列 这个题目就是 …

消息队列kafka详解:Kafka原理分析总结

一、概述 Kakfa起初是由LinkedIn公司开发的一个分布式的消息系统&#xff0c;后成为Apache的一部分&#xff0c;它使用Scala编写&#xff0c;以可水平扩展和高吞吐率而被广泛使用。目前越来越多的开源分布式处理系统如Cloudera、Apache Storm、Spark等都支持与Kafka集成。 Kaf…

EasyMock介绍及安装方法(亲测可用)

1. EasyMock介绍 Easy Mock是一个可视化&#xff0c;并且能快速生成模拟数据的服务。以项目管理的方式组织Mock List&#xff0c;能帮助我们更好的管理Mock数据&#xff0c;不怕丢失。 2. EasyMock魅力 前后端分离&#xff1a;让前端工程师独立于后端进行开发 增加单元测试…

SGPIO介紹

什么是SGPIO&#xff1f; Serial General Purpose Input Output (SGPIO) is a method to serialize general purpose IO signals. SGPIO defines the communication between an initiator (e.g. a host bus adapter) and a target (e.g. a backplaneholding disk drives). The …

美易官方:投行把脉明年油市,花旗悲观、高盛最看涨

投行把脉明年油市&#xff0c;花旗悲观、高盛最看涨 随着全球经济的逐步复苏&#xff0c;石油市场的走势备受关注。各大投行对明年油市的预测也各不相同&#xff0c;其中花旗集团较为悲观&#xff0c;而高盛集团则最为看涨。 华尔街的预测师们认为明年原油价格有一定的恢复空间…

最小窗口子串算法题——Java解答

题目&#xff1a;最小窗口子串 题目描述&#xff1a; 给你一个字符串 s 和一个字符串 t&#xff0c;返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串&#xff0c;则返回空字符串 ""。 注意&#xff1a; 对于 t 中重复的字符&#xff…

Axure的交互与情形,事件,动作

交互样式 交互样式是指当用户与原型进行交互时&#xff0c;元素所呈现出的视觉效果。在Axure中&#xff0c;可以通过设置交互样式来调整元素在交互过程中的外观&#xff0c;例如改变颜色、大小、位置等。 交互事件 交互事件是指在用户与原型进行交互时触发的动作。在Axure中&…

记录选择计算机专业后的这十二年,感谢当初自己选择了计算机行业

前言 这篇文章是对我这些年工作经历的回顾&#xff0c;您不会通过这篇文章提升自己的技术能力。如果您还未毕业&#xff0c;但是我希望您可以通过我的故事&#xff0c;简单了解这个行业可以能做什么&#xff0c;你可以做些什么。如果您初入此行业&#xff0c;希望我的故事可以…

一次应急响应记录

背景&#xff1a; 周五晚上&#xff0c;我健身完回到宿舍收到qq消息&#xff0c;原来是安全厂商在扫描资产时&#xff0c;发现一批openssh漏洞如下图&#xff1a; 其实我是一名小白&#xff0c;我的第一反应就是升级openssh版本。但是这里问题又来了&#xff0c;我们内网主机是…