Electron 入门

Electron入门

一、Electron 脚手架

1、添加 package.json

Electron + JS + 原生

nodemon 可以自动兼容文件变化,重启Electron客户端

{"name": "electron-app","version": "1.0.0","description": "","main": "main.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1","dev": "nodemon --exec electron ."},"keywords": [],"author": "","license": "ISC","dependencies": {"electron": "^28.0.0"},"devDependencies": {"nodemon": "^3.0.2"}
}

nodemon.json

{"ignore": ["node_modules","dist"],"colours": true,"verbose": true,"watch": ["*.*"],"ext": "html,js"
}

Electron + Vite + 任意框架

concurrently 执行同时执行多命令

{"name": "electron-vue","private": true,"version": "0.0.0","type": "module","main": "main.cjs","scripts": {"dev": "concurrently \"vite\" \"electron .\"","build": "vue-tsc && vite build","preview": "vite preview"},"dependencies": {"concurrently": "^8.2.2","electron": "^28.0.0","vue": "^3.3.8"},"devDependencies": {"@vitejs/plugin-vue": "^4.5.0","typescript": "^5.2.2","vite": "^5.0.0","vue-tsc": "^1.8.22"}
}

2、添加index.html

配置跨域

<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'" />

3、添加main.js

const createWindow = () => {const mainWindow = new BrowserWindow({width: 1000,height: 800,x: 20,y: 20,alwaysOnTop: false,frame: true,transparent: false,});mainWindow.loadURL(path.resolve(__dirname, 'index.html'));mainWindow.webContents.openDevTools();return mainWindow;
}app.whenReady().then(() => {createWindow();
})

另外推荐一个 React + TypeScript + Vite + Electron 的脚手架

https://github.com/maxstue/vite-reactts-electron-starter

二、Electron 进程通信

1、Electron 进程

Electron 主进程与渲染进程同时支持Node环境,但一般的,为了渲染进程安全,建议通过进程通信的方式在渲染进程中使用Node.

Electron 进程分为 主进程 main.js,渲染进程 renderer.js,预加载进程 preload.js

预加载进行用于预加载事件通信。

注册preload.js 预加载进程

const mainWindow = new BrowserWindow({webPreferences: {preload: path.resolve(__dirname, 'preload.js'),nodeIntegration: true,}
})

2、渲染进程向主进程发送消息

  1. 预渲染进程注册 IPC通道
contextBridge.exposeInMainWorld('api', {IPC_SET_TITLE: (preload) => ipcRenderer.send('CHANNEL_SET_TITLE', preload),
}
  1. 渲染进程向 IPC 通道发送消息
function createFormElement () {const input = document.createElement('input');input.name = 'title'const button = document.createElement('button');button.innerText = 'Submit'button.type = 'submit';const form = document.createElement('form');form.onsubmit = (event) => {event.preventDefault();const inputTitle = event.target.querySelector('input[name="title"]').valuewindow.api.IPC_SET_TITLE(inputTitle)}form.appendChild(input);form.appendChild(button);document.body.appendChild(form);
}
  1. 在主进程监听 IPC 通道消息
ipcMain.on('CHANNEL_SET_TITLE', (event, preload) => {//获取用于控制网页的webContents对象const webContents = event.sender//获取窗口const win = BrowserWindow.fromWebContents(webContents)//设置窗口标题win.setTitle(preload)
})

3、主进程向渲染进程发送消息

一个Electron菜单向页面发送消息的例子

  1. 预渲染进程注册 IPC通道
IPC_INCREMENT: (callback) => ipcRenderer.on('CHANNEL_INCREMENT', callback)

这里注册的是一个监听通道事件,它返回了一个回调函数,每当有通道消息,都会触发callback回调函数。

callback 它的类型大概是这样的

(event, preload) => any
  1. 菜单向IPC 通道发送消息

注册菜单:

// const mainWindow = new BrowserWindow(...)
createMenu(mainWindow);

menu.js

const { Menu } = require('electron')function createMenu(win) {const menu = Menu.buildFromTemplate([{label: '菜单',submenu: [{	//主进程向渲染进程发送消息click: () => win.webContents.send('CHANNEL_INCREMENT', 1),label: '增加',},],},]);Menu.setApplicationMenu(menu);
}module.exports = { createMenu }
  1. 重写 IPC_INCREMENT 函数,使其能够被 IPC通道 调用。

renderer.js

window.api.IPC_INCREMENT((event, value) => {const h1 = document.querySelector('h1');h1.innerHTML = Number(h1.innerText) + value;event.sender.send('CHANNEL_FINISH', h1.innerHTML); // 这个可以直接用// window.api.IPC_FINISH(h1.innerHTML); 这个需要在preload里先注册
})
  1. main.js
ipcMain.on('CHANNEL_FINISH', (event, preload) => {console.log(preload) // IDE 打印 1 2 3 4
})

4、Invoke 双向通信

  1. preload.js 注册通道
IPC_MAIN_SHOW: async (preload) =>  {console.log('IPC_MAIN_SHOW', preload);return ipcRenderer.invoke('CHANNEL_MAIN_SHOW', preload) // Promise<T>
}
  1. main.js 向通道 返回数据
app.whenReady().then(() => {createWindow();ipcMain.handle('CHANNEL_MAIN_SHOW', () => {return 'is main handle'})
})
  1. renderer 拿到通道 返回的数据,并向通道传入新的请求参数
function createInvokeButton () {const btn = document.createElement('button');btn.innerText = 'Invoke';btn.onclick = async () => {const res = await api.IPC_MAIN_SHOW('renderer');document.body.insertAdjacentText('afterend', res);}document.body.appendChild(btn)
}

三、进程隔离

参考文档:https://doc.houdunren.com/%E7%B3%BB%E7%BB%9F%E8%AF%BE%E7%A8%8B/electron/4%20%E9%9A%94%E7%A6%BB%E8%BF%9B%E7%A8%8B.html#%E4%B8%8A%E4%B8%8B%E6%96%87%E9%9A%94%E7%A6%BB

进程隔离有三个选项

contextIsolation 上下文隔离

nodeIntegration 集成Node

sandbox 沙盒环境

const mainWindow = new BrowserWindow({webPreferences: {preload: path.resolve(__dirname, 'preload.js'),contextIsolation: false,nodeIntegration: true,sandbox: false,},
})

隔离的配置有几种情况:

  • 默认 contextIsolation 为 true,nodeIntegration为 false,sandbox为true(安全,啥API用不了)

    • 此时main.js 为完全node环境,renderer 和 preload 为浏览器环境
  • nodeIntegration 为 true(推荐)

    • nodeIntegration 为 true,sandbox 自动设置 true,可以在preload中使用各种Node 高级模块,比如fs 等
  • nodeIntegration 为 true,sandbox为 false(不安全,啥API用不了)

    • 只能在preload 中用一些很低级的模块
  • contextIsolation为 false(不安全)

    • 不支持 contextBridge.exposeInMainWorld 等 API,在开启Node集成,关闭沙盒后,可以直接在render.js 中 使用完整的 NodeJS API,不安全

四、窗口定义

窗口实例常用的方法

方法说明
win.loadFile()加载文件
win.loadURL()加载链接
win.webContents.openDevTools()打开开发者工具
win.setContentBounds()控制窗口尺寸与位置
win.center()将窗口移动到屏幕中心

常用的窗口属性

属性说明
title标题,也可以修改html模板的title标签,模板的title标签优先级高
iconwindow系统窗口图标
frame是否显示边框
transparent窗口是否透明
xx坐标
yy坐标
width宽度
height高度
movable是否可以移动窗口
minHeight最小高度,不能缩放小于此高度
minWidth最大高度,不能缩放小于此高度
resizable是否允许缩放窗口
alwaysOnTop窗口是否置顶
autoHideMenuBar是否自动隐藏窗口菜单栏。 一旦设置,菜单栏将只在用户单击 Alt 键时显示
fullscreen是否全屏幕

五、菜单管理

在electron中可以方便的对应用菜单进行定义。

清除菜单

下面先来学习不显示默认菜单,在主进程main.js中定义以下代码。

const { BrowserWindow, app, Menu } = require('electron')
Menu.setApplicationMenu(null)

我们需要用到 Menu (opens new window)模块、MenuItem (opens new window)菜单项与 accelerator (opens new window)快捷键知识。

const { Menu, BrowserWindow } = require('electron')const isMac = process.platform === 'darwin'function createMenu(window) {const menu = Menu.buildFromTemplate([{label: '菜单',submenu: [{label: '打开新窗口',click: () => new BrowserWindow({ width: 800, height: 600 }).loadURL('https://baidu.com'),accelerator: 'CommandOrControl+n',},{ //主进程向渲染进程发送消息label: '增加',click: () => window.webContents.send('CHANNEL_INCREMENT', 1),},],},{type: 'separator',},isMac? { label: '关闭', role: 'close' }: { role: 'quit' },]);Menu.setApplicationMenu(menu);
}module.exports = {createMenu,
}

右键菜单

electron 可以定义快捷右键菜单,需要预加载脚本与主进程结合使用

main.js 主进程定义ipc事件,当preload.js 触发事件时显示右键菜单

ipcMain.on('show-context-menu', (event) => {const popupMenuTemplate = [{ label: '退出', click: () => app.quit() },]const menu = Menu.buildFromTemplate(popupMenuTemplate,)menu.popup(BrowserWindow.fromWebContents(event.sender),)
})

preload.js 预加载脚本定义,用于触发右键事件,然后通过IPC调用主进程显示右键菜单

window.addEventListener('contextmenu', (e) => {e.preventDefault()ipcRenderer.send('show-context-menu')
})

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

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

相关文章

Elasticsearch:使用 ELSER v2 进行语义搜索

在我之前的文章 “Elasticsearch&#xff1a;使用 ELSER 进行语义搜索”&#xff0c;我们展示了如何使用 ELESR v1 来进行语义搜索。在使用 ELSER 之前&#xff0c;我们必须注意的是&#xff1a; 重要&#xff1a;虽然 ELSER V2 已正式发布&#xff0c;但 ELSER V1 仍处于 [预览…

webrtc 中 FIR PLI 有何区别? 分别适用于什么场景

在WebRTC中&#xff0c;FIR&#xff08;Full Intra Request&#xff09;和PLI&#xff08;Picture Loss Indication&#xff09;是两种用于视频通信的控制消息&#xff0c;用于不同的场景。 FIR是一种请求全关键帧的控制消息。关键帧是视频序列中的特殊帧&#xff0c;它们不依…

【算法 - 动态规划】最长回文子序列

上篇文章中&#xff0c;我们学习一个新的模型&#xff1a; 样本对应模型&#xff0c;该模型的套路就是&#xff1a;以结尾位置为出发点&#xff0c;思考两个样本的结尾都会产生哪些可能性 。 而前篇文章中的 纸牌博弈问题 属于 [L , R]上范围尝试模型。该模型给定一个范围&…

C 嵌入式系统设计模式 08:硬件代理模式

本书的原著为&#xff1a;《Design Patterns for Embedded Systems in C ——An Embedded Software Engineering Toolkit 》&#xff0c;讲解的是嵌入式系统设计模式&#xff0c;是一本不可多得的好书。 本系列描述我对书中内容的理解。本文章描述访问硬件的设计模式之一&…

【C++语法基础】3.常用数学运算和位运算技巧(✨新手推荐阅读)

前言 在C编程中&#xff0c;数学运算是非常基础和常用的功能。C提供了多种数学运算符和函数&#xff0c;用于执行基本的数学计算&#xff0c;如加减乘除、取模运算以及位运算等。 一、加减乘除四则运算 C中的基本算术运算符包括加法()、减法(-)、乘法(*)、除法(/)。这些运算…

学习数据结构和算法的第12天

题目练习 合并两个有序数组 给你两个按 非递减顺序 排列的整数数组 nums1和 nums2&#xff0c;另有两个整数m和n&#xff0c;分别表示nums1和 nums2 中的元素数目。 请你 合并 nums2到nums1中&#xff0c;使合并后的数组同样按非递减顺序排列。 注意&#xff1a;最终&#…

Python - Pandas绘图

绘图 柱状图 tips[total_bill].plot.hist() plt.show()tips[[total_bill, tip]].plot.hist() plt.show()kde 图: tips[tip].plot.kde() plt.show()散点图: tips.plot.scatter(xtotal_bill, ytip) plt.show()六角星箱体图: tips.plot.hexbin(xtotal_bill, ytip, gridsize10…

Chrome关闭时出现弹窗runtime error c++R6052,且无法关闭

环境&#xff1a; Chrome 版本121 Win10专业版 问题描述&#xff1a; Chrome关闭时出现弹窗runtime error cR6052&#xff0c;且无法关闭 解决方案&#xff1a; 1.任务管理器打开&#xff0c;强制结束进程 2.再次打开谷歌浏览器&#xff0c;打开设置关于Chrome&#xff0…

IO进程线程day5作业

1、使用多线程完成两个文件的拷贝&#xff0c;第一个线程拷贝前一半&#xff0c;第二个线程拷贝后一半&#xff0c;主线程回收两个线程的资源 代码&#xff1a; #include<myhead.h>//定义文件拷贝函数 int copy_file(int start,int len) {int srcfd,destfd;//以只读的形…

Vue3之ref与reactive的基本使用

ref可以创建基本类型、对象类型的响应式数据 reactive只可以创建对象类型的响应式数据 接下来让我为大家介绍一下吧&#xff01; 在Vue3中&#xff0c;我们想让数据变成响应式数据&#xff0c;我们需要借助到ref与reactive 先为大家介绍一下ref如何使用还有什么注意点 我们需…

解决弹性布局父元素设置高自动换行,子元素均分高度问题(align-content: flex-start)

案例&#xff1a; <view class"abc"><view class"abc-item" v-for"(item,index) in 8" :key"index">看我</view> </view> <style lang"less">.abc{height: 100px;display: flex;flex-wrap: …

Web基础②nginx搭建与配置

目录 一.Nginx概述 1.定义 2.Nginx模块作用 &#xff08;1&#xff09;main模块 &#xff08;2&#xff09;stream服务模块 &#xff08;3&#xff09;邮件服务模块 &#xff08;4&#xff09;第三方模块 &#xff08;5&#xff09;events模块 &#xff08;6&#xff…

Python 进阶语法:JSON

1 什么是 JSON&#xff1f; 1.1 JSON 的定义 JSON 是 JavaScript Object Notation 的简写&#xff0c;字面上的意思是 JavaScript 对象标记。本质上&#xff0c;JSON 是轻量级的文本数据交换格式。轻量级&#xff0c;是拿它与另一种数据交换格式XML进行比较&#xff0c;相当轻…

Sora--首个大型视频生成模型

Sora--首个大型视频生成模型 胡锡进于2024年2月20日认为&#xff1a;台当局怂了 新的改变世界模拟器视觉数据转换视频压缩时空补丁&#xff08;Spacetime Laten Patches&#xff09;视频生成扩展变压器算法和模型架构结语 胡锡进于2024年2月20日认为&#xff1a;台当局怂了 **T…

六大设计原则 (SOLID)

一、设计原则概述 古人云: 有道无术,术可求.有术无道,止于术. 而设计模式通常需要遵循一些设计原则,在设计原则的基础之上衍生出了各种各样的设计模式。设计原则是设计要求,设计模式是设计方案,使用设计模式的代码则是具体的实现。 设计模式中主要有六大设计原则,简称为SOL…

conda 进入虚拟环境命令报错

问题描述 conda-script.py: error: argument COMMAND: invalid choice: activate 解决方案&#xff1a; 在终端命令先执行 conda init&#xff0c;重置conda环境。然后退出终端&#xff0c;重新进入终端即可conda activate env了。

【web | CTF】反序列化打法

天命&#xff1a;因为是php的上古版本&#xff0c;所以本机无法复现&#xff0c;只能用归纳法解决&#xff0c;就是题海战术找相同点&#xff0c;fuzz来测试新的题目 题目一&#xff1a;绕过正则和绕过__wakeup函数&#xff0c;private属性 【web | CTF】攻防世界 Web_php_uns…

【云原生】持续集成持续部署

本文主要总结CI/CD的流程&#xff0c;不会详细介绍每个知识点。 啥是集成&#xff1f;啥是部署&#xff1f; 集成&#xff0c;就是把应用程序、相关环境、配置全局打包放在一个容器中的操作。部署就不解释了。 CI/CD 如果是自己手动部署的话&#xff0c;流程应该是这样的&am…

FPS游戏漫谈之PVE AI技能和Buff属性描述

在Unity引擎中开发FPS射击游戏的PVE部分时&#xff0c;怪物AI的技能和buff属性可以分为静态属性和动态属性。 静态属性 静态属性是指那些在游戏开始之前就已经定义好&#xff0c;并且在游戏过程中不会改变的属性。这些属性包括但不限于&#xff1a; 技能的基础伤害值 技能的冷…

Global Gamers Challenge | 与 Flutter 一起保护地球

作者 / Kelvin Boateng 我们知道 Flutter 开发者热爱挑战&#xff0c;因此我们很高兴地宣布&#xff0c;新一轮的 Flutter 挑战赛来了&#xff01; 挑战https://flutter.cn/events/puzzle-hack Global Gamers Challenge 是一项为期 8 周的比赛&#xff0c;参赛者需要设计、构建…