Electron入门笔记
Electron入门笔记
- Electron
- Electron 是什么
- Electron流程模型
- 创建第一个Electron项目
- 配置自动重启
- 主进程和渲染进程通信
- 打包应用
Electron
Electron 是什么
- 跨平台的桌面应用开发框架
- 使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 嵌入 Chromium和 Node.js
Electron流程模型
-
主进程:
- 主进程只有一个
- 主要功能是管理渲染进程,与操作系统打交道。调用Native API 进行各种系统级的操作,并且可以跨平台
- node环境,能使用node的各种API,使用node的各个模块进行操作,没有浏览器相关的属性,无法访问window等浏览器属性
渲染进程:
-
渲染进程有多个
-
主要是程序的展示的窗口
-
浏览器环境,本质就是Chromium,能使用浏览器的各种API,无法使用node环境的API(
ctrl shift i
可以打开窗口的控制台,跟浏览器是一模一样的,ctrl R
可以刷新页面)
-
主进程和渲染进程是可以通信的,可以是渲染进程向主进程单向通信,也可以是主进程想渲染进程通信,也可以双向通信,进程间的通信称为IPC
-
总结:主进程(一个)管理各个渲染进程(多个),渲染进程跟主进程进行通信(渲染进程间无法直接通信,通过主进程作为中间人可以实现),主进程调用各种Native API 完成系统级操作
创建第一个Electron项目
-
环境:需要先安装Node.js
- 注意:先安装Node.js只是为了正确安装
electron
, 因为 Electron 将 Node.js 嵌入到其二进制文件中,你应用运行时的 Node.js 版本与你系统中运行的 Node.js 版本无关
- 注意:先安装Node.js只是为了正确安装
-
mkdir my-electron-app && cd my-electron-app yarn init
-
执行
yarn init
生成package.json
后author
和description
在打包阶段属于必填项 -
{"name": "electron-first","version": "1.0.0","main": "main.js","license": "MIT","author": "XiaoMing","description": "Hello World", }
-
安装
Electron
并在package.json
配置启动命令-
yarn add ELectron -D
-
{"scripts": {"start": "electron ." // 注意 . 不能省略} }
-
启动项目前需要创建主进程,也就是
package.json
中对应的main
,命名为main.js
, 否则会报错,创建完成后,执行yarn start
即可启动 -
此时启动无报错,但也无任何反应,因为没有在主进程里配置任何东西,渲染窗口等进程需要在主进程中配置
-
-
创建
pages
文件夹用于存放页面文件(也就是渲染进程的文件),分别创建对应的index.html
,index.css
,render.js
文件-
在
index.html
中引入css
和js
文件 -
html
的head
需要配置一个meta
,解决CSP的警官-
<metahttp-equiv="Content-Security-Policy"content="default-src 'self'; script-src 'self' 'unsafe-inline'" />
-
-
-
-
default-src 'self'
是一组配置,意思是如果不做出任何的说明,引入的外部资源,只能是属于同源
script-src 'self' 'unsafe-inline'
是另一组配置,指引入样式的时候,可以有两种写法,第一种写法
self
是可以引入同源的样式表,第二种写法unsafe-inline
可以使用行内样式
-
-
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8" /><!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP --><metahttp-equiv="Content-Security-Policy"content="default-src 'self'; script-src 'self' 'unsafe-inline'"/><title>Hello World!</title><link rel="stylesheet" href="./index.css" /></head><body><h1>Hello World!</h1>We are using Node.js <span id="node-version"></span>, Chromium<span id="chrome-version"></span>, and Electron<span id="electron-version"></span>.<script src="./render.js"></script></body> </html>
需要将写好的页面加载出来,如何加载页面,这个需要主进程进行控制,因此需要配置主进程main.js
-
const { app, BrowserWindow } = require("electron");const createWindow = () => {const win = new BrowserWindow({width: 800,height: 600,});win.loadFile("./pages/index.html"); };// app.whenReady().then(() => {}) 的写法与 app.on("ready", () =>{}) 同理app.on("ready", () => {createWindow();app.on("window-all-closed", () => {if (process.platform !== "darwin") app.quit();}); });
-
管理窗口的生命周期
-
关闭所有窗口时退出应用 (Windows & Linux),在Windows和Linux上,关闭所有窗口通常会完全退出一个应用程序。
// 为了实现这一点,你需要监听 app 模块的 'window-all-closed' 事件。如果用户不是在 macOS(darwin) 上运行程序,则调用 app.quit()。 app.on('window-all-closed', () => {if (process.platform !== 'darwin') app.quit() })
-
如果没有窗口打开则打开一个窗口 (macOS),macOS 应用通常即使在没有打开任何窗口的情况下也继续运行,并且在没有窗口可用的情况下激活应用时会打开新的窗口。
// 为了实现这一特性,监听 app 模块的 activate 事件。如果没有任何浏览器窗口是打开的,则调用 createWindow() 方法。 // 因为窗口无法在 ready 事件前创建,你应当在你的应用初始化后仅监听 activate 事件。 通过在您现有的 whenReady() 回调中附上您的事件监听器来完成这个操作。app.on("ready", () => {createWindow();app.on('activate', () => {if (BrowserWindow.getAllWindows().length === 0) createWindow()}) });
-
-
完整项目结构
-
启动项目
yarn start
配置自动重启
-
主进程每修改一次就得手动重启一次,可以配置自动重启
-
安装
nodemon
-
yarn add nodemon -D
-
-
更改启动命令
-
{"scripts": {"start": " nodemon --exec electron ."}, }
-
-
更改完启动命令发现自动重启的是主进程,但不改主进程,只改页面,发现页面窗口是需要手动刷新的,配置一个nodemon.json即可实现页面文件也能自动刷新
-
{"ignore": ["node_modules", "dist"],"restartable": "r","watch": ["*.*"],"ext": "html, css, js" }
-
主进程和渲染进程通信
-
目前主进程和渲染进程是没有什么关联的,主进程只是配置了加载渲染进程,然后他们之前没有其他的关系了,此时如果需要在渲染进程里拿到主进程中的node版本号是不可行的,因为渲染进程是浏览器环境,没有
process
属性 -
此时就需要一个预加载脚本作为主进程和渲染进程之间通信的桥梁,注意:预加载脚本可以拿到部分的node API,但不是所有
-
主进程目录下创建
preload.js
-
const { contextBridge } = require("electron");contextBridge.exposeInMainWorld("api", {version: process.version, });
-
-
主进程需要配置运行预加载脚本
-
const createWindow = () => {const win = new BrowserWindow({width: 800,height: 600,webPreferences: {preload: path.resolve(__dirname, "./preload.js"),},});win.loadFile("./pages/index.html"); };
-
-
配置一下渲染进程的脚本
-
const nodeVersion = document.querySelector("#node-version");console.log(window);nodeVersion.textContent = api.version;
-
-
最后结果
-
由此,引出,渲染进程跟主进程之间的相互通信,需要通过预加载脚本,因为预加载脚本也只能访问到node部分属性,像是文件操作等还是需要主进程来完成的
-
完成在窗口输入内容,并写入文件,最近将文件读出来的需求即可完全理解进程间的通信
-
main.js
-
const { app, BrowserWindow, ipcMain } = require("electron"); const path = require("path"); const fs = require("fs");const writeFile = (_, data) => {fs.writeFileSync(path.resolve(__dirname, "./hello.txt"), data); };const readFile = () => {return fs.readFileSync(path.resolve(__dirname, "./hello.txt")).toString(); };const createWindow = () => {const win = new BrowserWindow({width: 800,height: 600,webPreferences: {preload: path.resolve(__dirname, "./preload.js"),},});ipcMain.on("write-file", writeFile);ipcMain.handle("read-file", readFile);win.loadFile("./pages/index.html"); };app.on("ready", () => {createWindow();app.on("activate", () => {if (BrowserWindow.getAllWindows().length === 0) createWindow();}); });app.on("window-all-closed", () => {if (process.platform !== "darwin") app.quit(); });
-
-
preload.js
-
const { contextBridge, ipcRenderer } = require("electron");contextBridge.exposeInMainWorld("api", {version: process.version,writeFile: (data) => {ipcRenderer.send("write-file", data);},readFile: () => ipcRenderer.invoke("read-file"), });
-
-
render.js
-
const nodeVersion = document.querySelector("#node-version"); const input = document.querySelector("#input"); const write = document.querySelector("#write"); const read = document.querySelector("#read");nodeVersion.textContent = api.version;window.onload = () => {write.addEventListener("click", () => {api.writeFile(input.value);});read.addEventListener("click", async () => {const text = await api.readFile();alert(text);}); };
-
-
index.html
-
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8" /><!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP --><metahttp-equiv="Content-Security-Policy"content="default-src 'self'; script-src 'self' 'unsafe-inline'"/><title>Hello World!</title><link rel="stylesheet" href="./index.css" /></head><body><h1>Hello World!</h1>We are using Node.js <span id="node-version"></span>, Chromium<span id="chrome-version"></span>, and Electron<span id="electron-version"></span>.<hr /><input id="input" /><button id="write">写入文件</button><button id="read">读取文件</button><script src="./render.js"></script></body> </html>
-
打包应用
-
使用
electron build
打包成一个安装包应用 -
yarn add electron-build -D
-
electron-build
配置地址:CodeBlog/Electron/electron-builder打包详解.md at master · QDMarkMan/CodeBlog (github.com) -
配置
package.json
-
{"scripts": {"build": "electron-builder"},"build": {"appId": "com.electron.myapp","nsis": {"oneClick": false,"allowElevation": true,"allowToChangeInstallationDirectory": true},"win": {"icon": "./vite.svg","target": [{"target": "nsis","arch": ["x64"]}]}} }
-
-
electron-builder打包慢解决方法
- electron-builder 打包太慢解决方法build过程耗时较长,可以手动下载部分文件。镜像地址 https:/ - 掘金 (juejin.cn)
相关文章:

Electron入门笔记
Electron入门笔记 ElectronElectron 是什么Electron流程模型创建第一个Electron项目配置自动重启主进程和渲染进程通信打包应用 Electron Electron 是什么 跨平台的桌面应用开发框架使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 嵌入 Chromium和 Node.js Electro…...

python 不相交集简介(并查集算法)【Introduction to Disjoint Set (Union-Find Algorithm)】
什么是不相交集数据结构? 如果两个集合没有任何共同元素,则它们被称为不相交集,集合的交集为空集。 存储不重叠或不相交元素子集的数据结构称为不相交集合数据结构。不相交集合数据结构支持以下操作: 1、将新集合添加到不相交集合…...

23种设计模式之工厂方法模式
文章目录 1. 简介2. 代码2.1 抽象类:Course.java2.2 产品A:JavaCourse.java2.3 产品B:PythonCourse.java2.4 工厂抽象类:CourseFactory.java2.5 产品A的工厂A:JavaCourseFactory.java2.6 产品B的工厂B:PyCo…...

Redis——事务
文章目录 Redis 事务Redis 的事务和 MySQL 事务的区别:事务操作MULTIEXECDISCARDWATCHUNWATCHwatch的实现原理 总结 Redis 事务 什么是事务 Redis 的事务和 MySQL 的事务 概念上是类似的. 都是把⼀系列操作绑定成⼀组. 让这⼀组能够批量执行 Redis 的事务和 MySQL 事务的区别:…...
Redis非关系型数据库操作命令大全
以下是 Redis 的常用操作命令大全,涵盖了键值操作、字符串、哈希、列表、集合、有序集合、发布/订阅、事务等多个方面的操作。 1. 通用键命令 命令说明SET key value设置指定 key 的值GET key获取指定 key 的值DEL key删除指定的 keyEXISTS key检查 key 是否存在E…...

基于SpringBoot+Vue+uniapp微信小程序的澡堂预订的微信小程序的详细设计和实现
项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念,提供了一套默认的配置,让开发者可以更专注于业务逻辑而不是配置文件。Spring Boot 通过自动化配置和约…...

Linux mips架构链接库函数调用plt表汇编代码分析
linux调用共享库中的函数时通过plt表和got表实现位置无关代码,过程中涉及到lazy binding,即在第一调用外部函数时解析被调用的函数地址并将地址写入到got表,后续调用则不需要解析函数地址。这一部分和硬件架构有关,具体的是和cpu指…...

python 作业1
任务1: python为主的工作是很少的 学习的python的优势在于制作工具,制作合适的工具可以提高我们在工作中的工作效率的工具 提高我们的竞争优势。 任务2: 不换行 换行 任务3: 安装pycharm 进入相应网站Download PyCharm: The Python IDE for data science and we…...
Apache 出现 “403 forbidden“ 排查方法
1、检查运行 Apache 进程的用户没有对目录具备读取权限 如果该用户没有对 Directory 指定的目录具备适当的读取权限,就会导致 403 错误。 例如:使用用户apache启动Apache进程,但是apache用户对 Directory 指定的目录没有读取权限 2、检查…...
vue video播放m3u8监控视频
很关键的问题 vite创建的项目不需要import ‘videojs-contrib-hls’ 导入就报错 直接添加如下代码即可 html5: {vhs: {overrideNative: true},nativeVideoTracks: false,nativeAudioTracks: false,nativeTextTracks: false} 下面是完整组件示例 <template><div>…...

uniapp 获取签名证书 SHA1 自有证书签名打包
1.登录你的Dcloud 账户 2.找到我的应用菜单 3.点开某个应用 4.查看证书详情,里面有SHA1 和别名,密码,下载证书用于云打包,可以选择自有证书,输入别名,密码打包...
Open3d开发点云标注工具问题总结(二)
前面我们介绍了使用AABB方式来框选点云,但这种方式还是不够直观,我们的构想是设计一个和o3d.visualization.VisualizerWithEditing的点云框选方法一样的软件,因此,博主想到利用投影的形式进行解决: 具体的,…...

【FreeRTOS】
报错: 使用STM32cubemx自动生成freertos选项V2报错,V1不报错 …/Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/freertos_os2.h(31): 解决 修改cubemx配置,将V1.8.6改选为V1.8.5后编译不再报错...
洛谷 P4995:跳跳! ← 贪心算法
【题目来源】https://www.luogu.com.cn/problem/P4995【题目描述】你是一只小跳蛙,你特别擅长在各种地方跳来跳去。 这一天,你和朋友小 F 一起出去玩耍的时候,遇到了一堆高矮不同的石头,其中第 i 块的石头高度为 hi,地…...

代理 IP 在 AI 爬虫中的关键应用
现如今,人工智能(AI)的发展日新月异,而数据作为驱动 AI 发展的关键要素,其重要性不言而喻。AI 爬虫作为获取大量数据的重要工具,在数据收集过程中发挥着至关重要的作用。而代理 IP 在 AI 爬虫中有着广泛而重…...

【Vercel】Vercel静态部署踩坑
背景 在现代的软件开发中,自动化部署是一个不可或缺的环节。Vercel作为一个流行的前端部署平台,提供了与GitHub的无缝集成,使得开发者能够在每次提交代码后自动触发部署流程。然而,自动化部署过程中可能会遇到一些挑战࿰…...

【Spring】关于Spring中aware相关接口的作用
Aware 接口的回调方法是在 Bean 实例化之后调用的。具体来说,这些回调方法是在依赖注入完成后,但在 Bean 完全初始化之前调用的。这是 Spring 容器管理 Bean 生命周期的一部分 完成了属性赋值之后,Spring会执行一些回调,包括&…...

动态内存管理及RAII的简单应用
目录 一.程序启动所关联的内存分区 二.动态内存的申请和释放 三.将RAII思想融入代码 四.RAII思想的简单应用 一.程序启动所关联的内存分区 .dll文件是Dynamic Link Library(动态链接库)文件的缩写,它是一种共享库文件,包含…...

7、Vue2(一)
1.认识Vue 官网地址:https://v2.cn.vuejs.org/v2/guide/ Vue.js 是一套构建用户界面的渐进式框架。 Vue 2 是在2016年发布使用,2020是 vue3 才刚发布,时隔一年左右就已经将 vue3 作为了默认版本 尤雨溪,Vue.js和Vite的作者&…...
Chapter11
11.3 #include <stdio.h> #include <string.h> #define NUM_STUDENTS 40 #define NUM_SUBJECTS 3 // 学生结构体 typedef struct { int id; char name[50]; float scores[NUM_SUBJECTS]; float average; } Student; void inputData(Student studen…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器
——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的一体化测试平台,覆盖应用全生命周期测试需求,主要提供五大核心能力: 测试类型检测目标关键指标功能体验基…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...

【2025年】解决Burpsuite抓不到https包的问题
环境:windows11 burpsuite:2025.5 在抓取https网站时,burpsuite抓取不到https数据包,只显示: 解决该问题只需如下三个步骤: 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...

零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...

Linux 内存管理实战精讲:核心原理与面试常考点全解析
Linux 内存管理实战精讲:核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用,还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...

基于IDIG-GAN的小样本电机轴承故障诊断
目录 🔍 核心问题 一、IDIG-GAN模型原理 1. 整体架构 2. 核心创新点 (1) 梯度归一化(Gradient Normalization) (2) 判别器梯度间隙正则化(Discriminator Gradient Gap Regularization) (3) 自注意力机制(Self-Attention) 3. 完整损失函数 二…...