Electron 基础入门 简单明了,看完啥都懂了

您所在的位置:网站首页 electron开发ios Electron 基础入门 简单明了,看完啥都懂了

Electron 基础入门 简单明了,看完啥都懂了

2023-06-27 16:46| 来源: 网络整理| 查看: 265

image.png 什么是 Electron? 介绍 使用 JavaScript, HTML 和 CSS 构建跨平台(Windows、MacOs、Linux)的桌面应用——这是Electron官网的简介最初被GitHub开发,2013年4月11日以Atom Shell为名起步,2014年5月16日开源,2015年4月17日改名为Electron。

image.png

组成

image

Chromium : 为Electron提供了强大的UI能力,可以不考虑兼容性的情况下,利用强大的Web生态来开发界面。(本质上就是chromium(chrome开源版本)浏览器,有最新的东西都会在chromium测试,所以electron可以体验最新的api,这也是好处之一)

Chromium 多进程架构图

image.png

简单描述下。

主进程中的RenderProcessHost和 render 进程中的RenderProcess是用来处理进程间通信的(IPC(Inter-Process Communication,进程间通信)。

Render 进程中的 RenderView 内容基于 WebKit(浏览器引擎) 排版展示出来的

Render 进程中的ResourceDispatcher是用来处理资源请求的。Render 进程中如果有请求则创建一个请 求 ID,转发到 IPC,由 Browser 进程中处理后返回    

Chromium 是多进程架构,包括一个主进程,多个渲染进程

Node.js :让Electron有了底层的操作能力,比如文件的读写,甚至是集成C++等等操作,并可以使用大量开源的npm包来完成开发需求。

Native API : Native API让Electron有了跨平台和桌面端的原生能力,比如说它有统一的原生界面,窗口、托盘、消息通知这些。

通过三者的巧妙组合,我们开发应用变的十分高效。

Electron 架构 image.png

Electron 架构和 Chromium 架构类似,也是具有1个主进程和多个渲染进程。但是也有区别

在各个进行中暴露了 Native API ,提供了 Native 能力。引入了 Node.js,所以可以使用 Node 的能力但是渲染进程使用node 需要配置,下文会有所提到

可以简单的理解为Electron为web项目套上了Node.js环境的壳,使得我们可以调用Node.js的丰富的API。这样我们可以用JavaScript来写桌面应用,拓展很多我们在web端不能做的事情。

示意图

image.png

Electron 进程

electron核心我们可以分成2个部分,主进程和渲染进程。

主进程

image

Electron 运行 package.json 的 main 脚本的进程被称为主进程 (只有一个)

主进程特点: 主进程连接着操作系统和渲染进程,可以把她看做页面和计算机沟通的桥梁。进程间通信、窗口管理全局通用服务。一些只能或适合在主进程做的事情。例如浏览器下载、全局快捷键处理、托盘、session。维护一些必要的全局状态

渲染进程

image

渲染进程就是我们所熟悉前端环境了。只是载体改变了,从浏览器变成了window.

注:出于安全考虑,渲染进程是不能直接访问本地资源的),因此都需要在主进程完成。

渲染进程特点 Electron 使用了 Chromium 来展示 web 页面,所以 Chromium 的多进程架构也被使用到。每个web页面运行在它自己的渲染进程中。每个渲染进程都是相互独立的,并且只关心他们自己的网页。使用BrowserWindow类开启一个渲染进程并将这个实例运行在该进程中,当一个BrowserWindow实例被销毁后,相应的渲染进程也会被终止。渲染进程中不能调用原生资源,但是渲染进程中同样包含Node.js环境,所以可以引入Node.js(下文会提到:nodeIntegration )

主进程与渲染进程的区别 主进程使用 BrowserWindow 实例创建网页。每个 BrowserWindow 实例都在自己的渲染进程里运行着一个网页。当一个 BrowserWindow 实例被销毁后,相应的渲染进程也会被终止。主进程管理所有页面和与之对应的渲染进程。由于在网页里管理原生 GUI 资源是非常危险而且容易造成资源泄露,所以在网页面调用 GUI 相关的 APIs 是不被允许的。如果你想在网页里使用 GUI 操作,其对应的渲染进程必须与主进程进行通讯,请求主进程进行相关的 GUI 操作。

image.png

把它们想象成这样

Chrome(或其他浏览器)的每个标签页(tab)及其页面,就好比 Electron 中的一个单独渲染进程。即使关闭所有标签页,Chrome 依然存在。这好比 Electron 的主进程,能打开新的窗口或关闭这个应用。

image

Electron 优缺点 优点 上手简单 HTML、CSS、JS、Node 。npm包、UI框架 ,方便高效,能很轻松的实现很好看的UI 多端运行  快速构建“跨平台”(Windows、MacOs、Linux)的桌面级应用  开发时间短  相对其他跨平台方案(如 QT GTK+ 等),更稳定,bug少, 毕竟只要浏览器外壳跑起 来了就可以了,当然坑是少不了的  再也不用兼容多浏览器 只针对谷歌 但要兼容mac、Linux

缺点 安装包体积略大(打包了Chromium) 至少包含了一个浏览器的体积 ,每装一个 app 就相当于装一个 chrome性能不如原生应用,mac下丝滑一些,window就有点丢帧 卡、启动慢、新开一个进程,起步价就是一个nodejs的内存开销 loadURL加载远程页面白屏事件长,优化可采用 vscode 骨架屏

有哪些著名应用是用Electron开发

image.png

Postman、uTools、Typora、Atom、Brave浏览器 ......... 成千上万

Hello world 创建项目

最简单的目录

image.png

生成package.json文件并修改

npm init // 修改package.json { "name": "electron-app", "version": "1.0.0", "main": "main.js", "scripts": { "start": "electron ." }, "devDependencies": { "electron": "^10.1.5" } }

注意:控制台中文乱码可以使用

"start": "chcp 65001 && electron ." // utf8的值是65001

安装 Electron

npm install electron --save-dev // npm 安装会十分的慢,甚至是失败,可以先使用cnpm 淘宝镜像去下载,速度快 创建main.js文件 const { app, BrowserWindow } = require('electron') let mainWindow = null ; app.on('ready',()=>{ mainWindow = new BrowserWindow({ width:500, height:500, webPreferences:{ nodeIntegration:true //设置为true就可以在这个渲染进程中调用Node.js } }); mainWindow.loadFile('index.html'); // 加载本地文件 // mainWindow.loadURL('https://zhuiyi.ai/'); // 加载远程文件 mainWindow.webContents.openDevTools({ mode: 'bottom' }); // 控制台开关 mainWindow.on('close',(e)=>{ // 在窗口要关闭的时候触发 e.preventDefault(); // 避免进程意外关闭导致进程销毁 }); mainWindow.on('closed',()=>{ // 当窗口已经关闭的时候触发 }); });

app 模块是为了控制整个应用的生命周期设计的。

BrowserWindow参数: BrowserWindow | Electron 中文文档

创建html文件

Hello World! Hello World!

启动项目

electron .

image.png

运行过程

image.png

image.png

也许你现在还不能理解这个流程,但是你需要记住这个流程,只有我们记住这个流程后,在以后程序出现问题时,才可以很快的定位问题.

自定义菜单

使用到的模块

menu 模块 menu类可以用来创建原生菜单,它可用作应用菜单和 context 菜单,这个模块是一个主进程的模块,并且可以通过 remote 模块给渲染进程调用,每个菜单有一个或几个菜单项 menu items,并且每个菜单项可以有子菜单. Tray 模块 用一个 Tray 来表示一个图标,这个图标处于正在运行的系统的通知区 ,通常被添加到一个 context menu 上. remote 模块 提供了一种在渲染进程(网页)和主进程之间进行进程间通讯(IPC)的简便途径。

窗口菜单

// 创建菜单模板 const template = [{ label: '凤来怡洗浴会所', submenu: [ { label: '精品SPA', click:()=>{ console.log('SPA'); } }, {label: '泰式按摩'} ] }, { label: '大浪淘沙洗浴中心', submenu: [ {label: '来杯奶茶'}, {label: '来个拔罐'} ] } ]; // 一定是在ready生命周期中 创建进程时设置菜单 app.on('ready', () => { const m = Menu.buildFromTemplate(template); // 创建菜单模板 Menu.setApplicationMenu(m); });

需要注意的是,Menu属于是主线程下的模块,要在渲染进程中使用的话需要借助 remote模块

自定义右键菜单

const {remote} = require('electron') const rigthTemplate = [{ label: '粘贴', click: ()=>{ // 事件 } }, { label: '复制' } ] const m = remote.Menu.buildFromTemplate(rigthTemplate); window.addEventListener('contextmenu', function (e) { //阻止当前窗口默认事件 e.preventDefault(); //把菜单模板添加到右键菜单 m.popup({ window: remote.getCurrentWindow() }); });

渲染进程使用remote模块的前提

webPreferences: { enableRemoteModule: true // 在初始化窗口的时候 允许渲染进程使用Remote模块 否则报错 }

托盘图标菜单

let appIcon = null; app.on('ready', function(){ appIcon = new Tray(require('path').join(__dirname,'./assets/ban.png')); // 最好用path.join绝对位置方式应用图片 cosnt contextMenu = Menu.buildFromTemplate([ //菜单配置 { label: '退出', click: function () { app.quit(); } } ]); // 设置托盘悬浮提示 appIcon.setToolTip('never forget'); // 设置托盘菜单 appIcon.setContextMenu(contextMenu); // 单击托盘小图标显示应用 appIcon.on('click', function () { // 显示主程序 if(currentWin.isVisible()){ currentWin.hide(); }else{ currentWin.show(); } }); });

注意:appIcon 必须声明在app.on('ready)之外,防止被垃圾回收机制回收,导致托盘图标消失let appIcon = null; 

进程之间通信

主进程和渲染进程之间可以通过ipcRenderer 模块和 ipcMain 模块通信。

通信使用到的模块

ipcMain  模块 是类 EventEmitter 的实例.当在主进程中使用它的时候,它控制着由渲染进程(web page)发送过来的异步或同步消息.从渲染进程发送过来的消息将触发事件. ipcRenderer  模块 是一个 EventEmitter 类的实例. 它提供了有限的方法,你可以从渲染进程向主进程发送同步或异步消息. 也可以收到主进程的相应.

主进程 —> 渲染进程

// 入口文件 main.js中 例如菜单中触发 { label: '泰式按摩', click:()=>{ console.log('泰式按摩 '); currentWin.webContents.send('message','我是主进程发送的参数'); } } // 渲染进程 / web页面中 html (第一种方式) const {ipcRenderer} = require('electron') ipcRenderer.on('message', (event, data) => { console.log('>>>>>>>>params',data) //我是主进程发送的参数 }); //在创建窗口时 (第二种方式) 现阶段已经不推荐这样使用 容易报错坑多 currentWin.webContents.executeJavaScript(` const {ipcRenderer} = require('electron') ipcRenderer.on('message', (evt, data) => { console.log('>>>>>>>>params',data) //我是主进程发送的参数 }); `)

渲染进程 —> 主进程

// web 页面中 渲染进程 —> 主进程 发送参数 const {ipcRenderer} = require('electron'); let btn = document.getElementById('btn'); btn.onclick = function () { ipcRenderer.send('params','我是渲染进程发送的参数'); } //main.js文件中 ipcMain.on('params',(event,data)=>{ console.log('>>>>>>>>params',data) // 我是渲染进程发送的参数 }) 渲染 进程1 -> 渲染进程2 // 渲染进程1 web 页面中 const {ipcRenderer} = require('electron') ipcRenderer.send('params','9453913') // 渲染进程2 web 页面中 const {ipcRenderer} = require('electron') ipcRenderer.on('params','9453913') // 主进程作为中转 // 渲染进程1 -> 主进程 -> 渲染进程2 // 渲染进程2 -> 主进程 -> 渲染进程1

项目打包

通过electron-packager及electron-builder两种方式,将已有的electron应用打包成msi格式和exe可执行文件

electron-builder就是有比electron-packager有更丰富的的功能,支持更多的平台,同时也支持了自动更新。除了这几点之外,由electron-builder打出的包更为轻量,并且可以打包出不暴露源码的setup安装程序

npm install electron-builder --save-dev

在package.json中做如下配置

"scripts": { "start": "electron .", "pack": "electron-builder --win --x64" }, "build": { "appId": "test.app", "productName": "测试项目", "mac": { "target": ["dmg","zip"] }, "win": { "target": ["nsis","zip"] } }

注意:mac的dmg包 需要macos签名,所以最好mac打dmg的包

常见的报错 end.jpg require is not defined

image.png

远程渲染页面(loadURL),页面使用require('electron'),容易报require 错误 undefined等,以下方法可解决

// 配置窗口时 添加 preload webPreferences: { nodeIntegration: true, //渲染进程允许使用node preload: path.join(__dirname, '../static/preload.js'), // electron 与 独立vue项目使用 }

preload.js

/** * 挂在electron 在全局 在远程页面中可以读取 */ window.electron = require('electron'); currentWin.webContents.executeJavaScript(不推荐使用)

image.png

image.png



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3