Electron - 跨平台桌面应用开发工具的使用总结

文章目录

    • 一、使用electron-vite新建项目
    • 二、目录结构
    • 三、渲染进程调用主进程
      • 1、方式一 —— 允许有返回值
        • · src/main/index.js
        • · src/preload/index.js
        • · src/renderer/index.html
      • 2、方式二—— 允许有返回值 (推荐写法)
        • · src/main/index.js
        • · src/preload/index.js
        • · src/renderer/index.html
      • 3、方式三 —— 无返回值,不等待响应
        • · src/main/index.js
        • · src/preload/index.js
        • · src/renderer/index.html
    • 四、主进程触发渲染进程
      • · src/main/index.js
      • · src/preload/index.js
      • · src/renderer/index.html
    • 五、功能介绍
      • 1、透明窗口设置
      • 2、系统截图功能
      • 3、系统托盘图标及闪烁功能
    • 六、问题处理
      • 1、图标打包路径无法获取问题
        • · 修改图标路径获取
      • 2、允许更改安装目录
        • · package.json 配置
      • 3、loadFile添加参数
      • 4、http数据请求与cookie设置
      • 5、iframe CSP
      • 6、多页面打包
        • · electron.vite.config.mjs
      • 7、路由切换主进程代码多次执行
    • 七、npm库
    • References

一、使用electron-vite新建项目

  • 1、npm命令 npm create @quick-start/electron
  • 2、yarn命令 yarn create @quick-start/electron
  • 3、electron镜像地址:
electron_mirror=https://npmmirror.com/mirrors/electron/
electron_builder_binaries_mirror=https://npmmirror.com/mirrors/electron-builder-binaries/
  • 4、填写项目名称
? Project name: electron-vue-app 
  • 5、选择vue框架:
? Select a framework: vanilla
>   vuereactsveltesolid
  • 6、其他配置项
? Add TypeScript? » No / Yes   
Yes
? Add Electron updater plugin? » No / Yes 
Yes
? Enable Electron download mirror proxy? » No / Yes
Yes

二、目录结构

├─ /.vscode
├─ /build
├─ /node_modules
├─ /out                         # 运行时的输出目录
├─ /resources                   # 主进程和预加载脚本资源文件目录
├─ /src
|  ├─ /main                     # Electron主进程
|  ├─ /preload                  # Electron预加载脚本
|  └─ /renderer                 # Electron渲染进程, vue常规目录结构
|  |  ├─ /assets
|  |  ├─ /components
|  |  ├─ /views
|  |  ├─ App.vue
|  |  ├─ main.js
|  |  └─ index.html
├─ .editorconfig
├─ .eslintignore
├─ .eslintrc.cjs
├─ .gitignore
├─ .npmrc
├─ .prettierignore
├─ .prettierrc.yaml
├─ dev-app-update.yml
├─ electron-builder.yml
├─ electron.vite.config.mjs
├─ package.json
├─ README.md

三、渲染进程调用主进程

1、方式一 —— 允许有返回值

· src/main/index.js
import { app, ipcMain, BrowserWindow } from 'electron'
app.whenReady().then(() => {// ...new BrowserWindow({width: 800,height: 600,// 其他窗口配置...})ipcMain.handle('renderderCallMain', async (event, value) => {console.log('renderder call main...', value)})// ...
})
· src/preload/index.js
import { contextBridge } from 'electron'
import { electronAPI } from '@electron-toolkit/preload'
if (process.contextIsolated) {try {contextBridge.exposeInMainWorld('electron', electronAPI)} catch (error) {console.error(error)}
} else {window.electron = electronAPI
}
· src/renderer/index.html
window.electron.ipcRenderer.invoke('renderderCallMain', 'hello world!')

2、方式二—— 允许有返回值 (推荐写法)

· src/main/index.js
import { app, ipcMain, BrowserWindow } from 'electron'
app.whenReady().then(() => {// ...new BrowserWindow({width: 800,height: 600,// 其他窗口配置...})ipcMain.handle('renderderCallMain', async (event, value) => {console.log('renderder call main...', value)})// ...
})
· src/preload/index.js
import { contextBridge, ipcRenderer } from 'electron'const call = {renderderCallMain: (value) => ipcRenderer.invoke('renderderCallMain', value),
}if (process.contextIsolated) {try {contextBridge.exposeInMainWorld('call', call)} catch (error) {console.error(error)}
} else {window.call = call
}
· src/renderer/index.html
window.call.renderderCallMain('hello world!')

3、方式三 —— 无返回值,不等待响应

· src/main/index.js
import { app, ipcMain, BrowserWindow } from 'electron'
app.whenReady().then(() => {// ...new BrowserWindow({width: 800,height: 600,// 其他窗口配置...})ipcMain.on('ping', () => console.log('pong'))// ...
}
· src/preload/index.js
import { contextBridge, ipcRenderer } from 'electron'const call = {ping: () => ipcRenderer.send('ping'),
}if (process.contextIsolated) {try {contextBridge.exposeInMainWorld('call', call)} catch (error) {console.error(error)}
} else {window.call = call
}
· src/renderer/index.html
window.call.ping()

四、主进程触发渲染进程

· src/main/index.js

import { app, globalShortcut, BrowserWindow } from 'electron'
app.whenReady().then(() => {// ...const mainWindow = new BrowserWindow({width: 800,height: 600,// 其他窗口配置...})globalShortcut.register('CommandOrControl+S', () => {mainWindow.webContents.send('commandOrControlS', 'command or control + s...')})// ...
})

· src/preload/index.js

import { contextBridge, ipcRenderer } from 'electron'
const listen = {commandOrControlS: (callback) => ipcRenderer.on('commandOrControlS', async (event, value) => callback(value)),
}if (process.contextIsolated) {try {contextBridge.exposeInMainWorld('listen', listen)} catch (error) {console.error(error)}
} else {window.listen = listen
}

· src/renderer/index.html

window.listen.commandOrControlS((value) => {console.log(value)
})

五、功能介绍

1、透明窗口设置

const mainWindow = new BrowserWindow({width: 80,height: 162,frame: false,                   // 透明窗口transparent: true,              // 透明窗口backgroundColor: '#00000000',   // 透明窗口autoHideMenuBar: true,          // 透明窗口
})

2、系统截图功能

import { desktopCapturer } from 'electron'async function desktopCapturerHandle() {const sources = await desktopCapturer.getSources({types: ['window'],thumbnailSize: {width: 1920,height: 1080,},})return sources[0]?.thumbnail.toDataURL('image/png'),
}

3、系统托盘图标及闪烁功能

import { app, BrowserWindow, Tray, Menu } from 'electron'let flickerTimer = nullapp.whenReady().then(() => {// ...const mainWindow = new BrowserWindow({width: 800,height: 600,// 其他窗口配置...})const tray = new Tray('./icon.ico')const contextMenu = Menu.buildFromTemplate([{ label: '显示       ', click: () => {mainWindow.show()stopTray(tray)}},{ type: 'separator' },{ label: '退出       ', click: () => {mainWindow.off('close', closeHandle)app.quit()}},])tray.setContextMenu(contextMenu)tray.on('double-click', function() {mainWindow.show() // 点击图标时恢复窗口stopTray(tray)})tray.on('click', function() {if (flickerTimer) {mainWindow.show() // 点击图标时恢复窗口stopTray(tray)}})// ...
})function flickerTray(tray) {if (!flickerTimer) {let hasIco = falseflickerTimer = setInterval(() => {// 图标与透明图标切换以实现闪烁功能tray.setImage(hasIco ? './icon.ico' : './empty.ico')hasIco = !hasIco}, 500)}
}function stopTray(tray) {if (flickerTimer) {clearInterval(flickerTimer)flickerTimer = null}tray.setImage('./icon.ico')
}

六、问题处理

1、图标打包路径无法获取问题

· 修改图标路径获取
import { app } from 'electron'
const path = require('path')function resolvePath() {const publicPath = 'build'const fileName = 'icon.ico'if (process.env.NODE_ENV === 'development') {return './' + publicPath + '/' + fileName}return path.join(path.dirname(app.getPath('exe')), '/resources/' + publicPath + '/' + 'fileName')
}
· package.json 配置图标打包
{..."build": {"extraResources": [{"from": "./build","to": "./build"}]}...
}

图标大小需 256x256,格式为ico

2、允许更改安装目录

· package.json 配置
{..."build": {"nsis": {"allowToChangeInstallationDirectory": true, // 允许更改安装目录"installerIcon": "./build/icon.ico",        // 安装图标"uninstallerIcon": "./build/icon.ico",      // 卸载图标"installerHeaderIcon": "./build/icon.ico",  // 安装程序头部图标"createDesktopShortcut": true,              // 创建桌面快捷方式"createStartMenuShortcut": false,           // 加入开始菜单}}...
}

3、loadFile添加参数

import { app, BrowserWindow } from 'electron'
import { join } from 'path'app.whenReady().then(() => {// ...const mainWindow = new BrowserWindow({width: 800,height: 600,// 其他窗口配置...})mainWindow.loadFile(join(__dirname, '../renderer/index.html'), {search: 'id=test',})// ...
})

4、http数据请求与cookie设置

  • 1)、由于 fill:// 协议无法设置cookie,所以请求只能在主进程发起
  • 2)、使用Chromium的原生网络库发出HTTP / HTTPS请求 或 Node.js的HTTP 和 HTTPS 模块
const { app } = require('electron')app.whenReady().then(() => {const { net } = require('electron')const request = net.request('https://github.com')request.on('response', (response) => {console.log(response)response.on('data', (chunk) => {console.log('BODY: ' + chunk)})response.on('end', () => {console.log('No more data in response.')})})request.end()
})
  • 3)、从请求结果中 set-cookie 获取cookie并返回给渲染端进行存储

5、iframe CSP

<meta http-equiv="Content-Security-Policy"content="script-src 'self' https://example.com; img-src https://example.com"
/>

修改html中的meta属性,这将允许在iframe中加载来自 selfexample.com 域的脚本,并允许加载来自 example.com 域的图像

6、多页面打包

· electron.vite.config.mjs
export default defineConfig({renderer: {build: {rollupOptions: {input: {index: './src/renderer/index.html',other: './src/renderer/other.html',}}}}
})

7、路由切换主进程代码多次执行

检查 ipcRenderer.on() 路由切换后是否多次在 onMounted 注册,需在 onBeforeUnmount 中及时调用主进程 ipcRenderer.removeListener() 注销事件的监听

七、npm库

  • 1、"@jitsi/robotjs": "^0.6.11" 适用于自动化工具,有控制I/O、系统截图等功能
  • 2、"tesseract.js": "^5.0.5" 基于js的图像识别
  • 3、"jimp": "^0.22.12" 图像处理工具,有图片裁剪、保存、图片大小更改等功能
  • 4、"nodemailer": "^6.9.13" 基于node的邮件发送工具

References

[1] Electron文档
[2] 基于electron-vite构建Vue桌面客户端

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

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

相关文章

shell脚本-重定向与管道符

一、重定向 因为shell脚本有着批量操作的特殊性&#xff0c;大部分操作处于后台执行&#xff0c;不需要用户进行干预&#xff0c;所以提取、过滤并执行信息十分需要重定向和管道。重定向的意思是不输出到默认设备上&#xff0c;而是输出到你指定的位置&#xff08;文件、其他输…

scrapy 使用Selenium与Scrapy处理动态加载网页内容的解决方法

引言 在爬虫技术领域&#xff0c;处理动态加载的网页内容常常是一项挑战&#xff0c;尤其是对于那些通过用户滚动或其他交互动态加载更多内容的网站。本文将介绍如何结合使用Selenium和Scrapy来有效处理这类网页。 初探Selenium与Scrapy的结合 首先&#xff0c;我们探索如何使…

1.微信小程序开发之准备工作

1.微信小程序账号注册 小程序开发 与 网页开发不一样&#xff0c;在开始微信小程序开发之前&#xff0c;需要访问 微信公众平台&#xff0c;注册一个微信小程序账号。 在拥有了小程序的账号以后&#xff0c;我们才可以开发和管理小程序&#xff0c;后续可以通过该账号进行开发…

springboot分页

1.代码分页 List<TbAjltData> pageViewList list.stream().skip((pageDomain.getPageNum() - 1) * pageDomain.getPageSize()).limit(pageDomain.getPageSize()).collect(Collectors.toList());2. Overridepublic List<TbAjk> selectTbAjkList(TbAjk tbAjk, Pag…

国网电力分公司、税务企业如何向央媒投稿?

税务、电力、银行等单位如果想要将稿件发布到中央媒体&#xff0c;可以遵循为大家整理的以下步骤和建议&#xff1a; 了解央媒的定位与要求&#xff1a;中央媒体&#xff0c;如新华社、人民日报、中央电视台等&#xff0c;都有其独特的报道风格和关注重点。在投稿前&#xff0…

【Web后端】会话跟踪技术及过滤器

1.会话跟踪技术 1.1 会话的概念 在web应用中&#xff0c;浏览器和服务器在一段时间内发送请求和响应的连续交互的全过程 1.2 会话跟踪概念 对同一个用户跟服务器的连续请求和接收响应的监视过程 1.3 会话跟踪作用 浏览器和服务器是以http协议进行通信&#xff0c;http协议是…

SD1005S控制电路LED光源恒流控制模块驱动放大器

SD1005S是一个集控制电路与发光电路于一体的智能外控LED光源。其外型与一个5050LED灯珠相同,每个 元件即为一个像素点。像素点内部包含了智能数字接口数据锁存信号整形放大驱动电路&#xff0c;防反接电路&#xff0c;还包含有 高精度的内部振荡器和高精度恒流控制模块&#xf…

LM3658单芯片充电器电源适配器50mA-1000mA充电电流

该LM3658是一个单芯片充电器IC专为手持应用。它 可以通过AC电源适配器或USB电源对单节锂离子/聚 合物电池进行安全充电和维护。USB/AC的输入电源 选择是自动的。两个电源同时存在时&#xff0c;交流电源优先 。当使用AC墙壁适配器时&#xff0c;充电电流通过外部电阻器 编程&am…

算法工程师面试问题 | YOLOv8面试考点原理全解析(一)

本文给大家带来的百面算法工程师是深度学习目标检测YOLOv8面试总结&#xff0c;文章内总结了常见的提问问题&#xff0c;旨在为广大学子模拟出更贴合实际的面试问答场景。在这篇文章中&#xff0c;我们还将介绍一些常见的深度学习目标检测面试问题&#xff0c;并提供参考的回答…

Vue中<style>标签的scoped属性

Vue中style标签的scoped属性 一、前言1、举例 二、总结 一、前言 scoped 是 Vue 中 <style> 标签的一个特殊属性&#xff0c;用于限定样式的作用范围。当你在 Vue 单文件组件&#xff08;.vue 文件&#xff09;中使用 <style scoped> 标签时&#xff0c;该样式只会…

树结构,JS某个节点的父节点 兄弟节点 以及子节点

获取某个节点的所有父节点: function getAllParentNodes(list, id) {for (let i in list) {if (list[i].id id) {return [list[i]].filter((v) > v.id ! id);}if (list[i].children?.length > 0) {let node getAllParentNodes(list[i].children, id);if (node) retur…

AWS RDS ElasticCache 监控可观测最佳实践

在当今的电子商务时代&#xff0c;一个高效、稳定的电商平台对于保持竞争力至关重要。数据库作为电商平台的核心支撑&#xff0c;其性能直接影响到用户体验和业务流畅度。本文将深入探讨如何在电商场景下通过观测云对亚马逊云科技 RDS&#xff08;MySQL&#xff09; 和 Elastic…

python+selenium - UI自动框架之封装log类

通过自定log类&#xff0c;能把执行过程记录到日志&#xff0c;方便检查和重现问题。 log类介绍&#xff1a; 每次调用log函数&#xff0c;会根据绝对路径生成日志文件在logs目录下面(在被调用的时候日志会输出到指定的文件&#xff09;&#xff0c;日志文件的格式是年月日.lo…

vue+element的表格(el-table)排班情况表(2024-05-09)

vueelement的表格&#xff08;el-table&#xff09;排班情况&#xff0c;增删查改等简单功能 代码&#xff1a; <template><!-- 表格 --><div class"sedules"><el-header><el-date-pickerv-model"monthValue2"type"month…

postgresql中控制符带来的数据错觉

简介 在数据库字符集中&#xff0c;由于数据质量的控制不够完善&#xff0c;每一个字符集都并不是所有字符的能看见&#xff0c;有些字符的展示可能会出现乱码&#xff0c;甚至出现不同字符展示成同样效果的可能&#xff0c;给开发人员造成分析错觉。 当数据库存入了控制符&am…

【Unity Shader入门精要 第7章】基础纹理(三)

1. 渐变纹理 另外一种对于纹理的使用方式是通过渐变纹理为物体提供漫反射光照效果。 顾名思义&#xff0c;渐变纹理本身就是一张颜色渐变&#xff08;可以是连续渐变&#xff0c;也可能是突变&#xff09;的图片&#xff0c;这个渐变的过程模拟的就是光源从不同的角度照射物体…

Win11下Java环境安装指南

Windows下Java环境安装指南 前言一、安装简介JDK与JRE安装包 二、JDK安装检查操作系统类型基于Win11基于Win10 安装包准备工作 三、配置环境配置JAVA_HOME配置Path配置CLASSPATH 四、检验配置是否打开cmd命令行窗口输出java -version命令 五、注意事项 前言 在Windows系统上安…

移动机器人的机动性

移动机器人的机动性 机器人底盘运动学的活动性是表示它在环境中直接运动的能力。限制活动性的基本约束是每一轮子必须满足它的滑动约束的规则。所以,我们可从方程(3.26)正式地推导机器人的活动性。 除了瞬时的运动学运动之外,移动机器人通过操纵可操纵的轮子,能够随时操纵它的…

基于springboot实现的教师人事档案管理系统

开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&…

mysql 拆分字段为多行

留备 原数据idname1张三,李四,王二2zhangsan,lisi,wanger目标数据idname1张三1李四1王二2zhangsan2lisi2wanger select t.id, substring_index(substring_index(t.name,,,t1.help_topic_id1),,,-1) name from zq.test t inner join mysql.help_topic t1 on t1.he…