electron基础入门

1. Electron是什么

Electron是一个跨平台桌面应用开发框架,开发者可以使用:HTML,CSS,JavaScript等Web技术来构建桌面应用程序,它的本质是结合了Chromium和Node.js,现在广泛用于桌面应用程序开发。

2. Electron 的优势

1. 可跨平台:同⼀套代码可以构建出能在:Windows、macOS、Linux 上运⾏的应⽤程序。 2. 上⼿容易:使⽤ Web 技术就可以轻松完成开发桌⾯应⽤程序。 3. 底层权限:允许应⽤程序访问⽂件系统、操作系统等底层功能,从⽽实现复杂的系统交互。 4. 社区⽀持:拥有⼀个庞⼤且活跃的社区,开发者可以轻松找到⽂档、教程和开源库

3. Electron 技术架构

3.1. 技术架构

![](https://i-blog.csdnimg.cn/img_convert/e3ae2121c04a310b5ab89a1c31b74492.png)

3.2. 进程模型

![](https://i-blog.csdnimg.cn/img_convert/38d9162397e38eaac18383943bce1f17.png)

4. 搭建⼀个⼯程

● 初始化⼀个包,并提填写好 package.json 中的必要信息及启动命令。
{
"name":"test",
"version":"1.0.0",
"main":"main.js",
"scripts": {
  "start": "electron ." //start命令⽤于启动整个应⽤
},
"author": "tianyu", //为后续能顺利打包,此处要写明作者。
"license": "ISC",
"description": "this is a electron demo", //为后续能顺利打包,此处要编写描述。
}

● 安装 electron 作为开发依赖。

npm i electron -D

● 在 main.js 中编写代码,创建⼀个基本窗⼝

/*
main.js运⾏在应⽤的主进程上,⽆法访问Web相关API,主要负责:控制⽣命周期、显示界⾯、控制渲染进程等其他操作
*/
const { app, BrowserWindow } = require('electron')

// ⽤于创建窗⼝
function createWindow() {
    const win = new BrowserWindow({ 
        width: 800, // 窗⼝宽度 height: 600, // 窗⼝⾼度
        autoHideMenuBar: true, // ⾃动隐藏菜单栏
        alwaysOnTop: true, // 置顶
        x: 0, // 窗⼝位置x坐标
        y: 0 // 窗⼝位置y坐标
    })
    // 加载⼀个远程⻚⾯
    win.loadURL('http://www.atguigu.com')
}

// 当app准备好后,执⾏createWindow创建窗⼝
app.on('ready',()=>{ 
    createWindow()
})

关于 BrowserWindow 的更多配置项,请参考:BrowserWindow实例属性

● 启动应⽤查看效果

npm start

● 效果如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

**5.** 加载本地⻚⾯

● 创建 pages/index.html 编写内容:
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>index</title>

    </head>

    <body>
        <h1>你好啊!</h1>

    </body>

</html>

● 修改 mian.js 加载本地⻚⾯

// 加载⼀个本地⻚⾯
win.loadFile('./pages/index.html')

● 此时开发者工具会报出一个安全警告,需要修改index.html,配置CSP(Content-Security-Policy)

<meta http-equiv="Content-Security-Policy" content="default-src 'self'; st yle-src 'self' 'unsafe-inline'; img-src 'self' data:;">

上述配置的说明

1. default-src __‘self’__****

default-src :配置加载策略,适⽤于所有未在其它指令中明确指定的资源类型。

self :仅允许从同源的资源加载,禁⽌从不受信任的外部来源加载,提⾼安全性。

2. style-src ‘self’ 'unsafe-*****inline’__*****

style-src :指定样式表(CSS)的加载策略。

self :仅允许从同源的资源加载,禁⽌从不受信任的外部来源加载,提⾼安全性。

unsafe-inline :允许在HTML⽂档内使⽤内联样式。

3. img-src ‘self’ data:

img-src :指定图像资源的加载策略。

self :表示仅允许从同源加载图像。

data: :允许使⽤ data: URI 来嵌⼊图像。这种URI模式允许将图像数据直接嵌

⼊到HTML或CSS中,⽽不是通过外部链接引⽤。

关于 CSP 的详细说明请参考:MDN-Content-Security-PolicyElectron Security

**6.** **完善窗⼝⾏为**

1,Windows 和 Linux 平台窗⼝特点是:关闭所有窗⼝时退出应⽤
// 当所有窗⼝都关闭时
app.on('window-all-closed', () => {
// 如果所处平台不是mac(darwin),则退出应⽤。
    if (process.platform !== 'darwin') app.quit()
})

2,mac 应⽤即使在没有打开任何窗⼝的情况下也继续运⾏,并且在没有窗⼝可⽤的情况下激活应⽤时会打开新的窗⼝。

// 当app准备好后,执⾏createWindow创建窗⼝
app.on('ready',()=>{ 
    createWindow()
    // 当应⽤被激活时
    app.on('activate', () => {
    //如果当前应⽤没有窗⼝,则创建⼀个新的窗⼝
    if (BrowserWindow.getAllWindows().length === 0)         createWindow()
    })
})

**7.** 配置自动重启

1. 安装 Nodemon
npm i nodemon -D
  1. 修改 package.json 命令
"scripts": {
    "start": "nodemon --exec electron ."
},
  1. 配置 nodemon.json 规则
{
    "ignore": [ 
        "node_modules", 
        "dist"
    ],
    "restartable": "r", 
    "watch": ["*.*"],
    "ext": "html,js,css"
}

配置好以后,当代码修改后,应⽤就会⾃动重启了

**8.** 主进程与渲染进程

下图是 Chrome 浏览器的程序架构,图来⾃于[Chrome 漫画](https://www.google.com/googlebooks/chrome/)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Electron 应⽤的结构与上图⾮常相似,在 Electron 中主要控制两类进程:主进程、渲染器进程

8.1. 主进程

每个 Electron 应⽤都有⼀个单⼀的主进程,作为应⽤程序的⼊⼝点。 主进程在 Node.js 环境中运⾏,它具有 require 模块和使⽤所有 Node.js API 的能⼒,主进程的核⼼就是:**使用BrowserWindow来创建和管理窗口**

8.2. 渲染进程

每个 BrowserWindow 实例都对应⼀个单独的渲染器进程,运⾏在渲染器进程中的代码,必须遵守⽹⻚标准,这也就意味着:**渲染器进程无权直接访问 **`require`** 或使用任何 **`Node.js`** 的 **`API`

问题产⽣:处于渲染器进程的⽤户界⾯,该怎样才与 Node.js 和 Electron 的原⽣桌⾯功能进⾏交互呢?

**9.** Preload 脚本

预加载(Preload)脚本是运⾏在渲染进程中的, 但它是在**网页内容加载之前**执⾏的,这意味着它具有⽐普通渲染器代码更⾼的权限,可以访问 Node.js 的 API,同时⼜可以与⽹⻚内容进⾏安全的交互。

简单说:它是 Node.js 和 Web API 的桥梁,Preload 脚本可以安全地将部分 Node.js 功能暴露给⽹⻚,从⽽减少安全⻛险。

需求:点击按钮后,在网页呈现当前的 Node 版本。

具体⽂件结构与编码如下:

  1. 创建预加载脚本 preload.js ,内容如下:
const {contextBridge} = require('electron')

// 暴露数据给渲染进程
contextBridge.exposeInMainWorld('myAPI',{ 
    n:666,
    version:process.version
})
  1. 在主线程中引⼊ preload.js
const win = new BrowserWindow({
    webPreferences:{
        preload:path.resolve(	dirname,'./preload.js')
    }
})
  1. 在 html ⻚⾯中编写对应按钮,并创建专⻔编写⽹⻚脚本的 render.js ,随后引⼊。
<body>
    <h1>你好啊!</h1>

    <button id="btn">在⽤户的D盘创建⼀个hello.txt</button>

    <script type="text/javascript" src="./render.js"></script>

</body>

  1. 在渲染进程中使⽤ version
btn.addEventListener('click',()=>{ 
    console.log(myAPI.version)
    document.body.innerHTML += `<h2>${myAPI.version}</h2>`
})
  1. 整体⽂件结构如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

10.进程通信(IPC)

> 值得注意的是: > > 上⽂中的 `preload.js` ,⽆法使⽤全部 `Node` 的 `API` ,⽐如:不能使⽤ `Node` 中的 `fs` 模块,但主进程( `main.js` )是可以的,这时就需要_**进程通信**_了。简单说:要 > > 让 `preload.js` 通知 `main.js` 去调⽤ `fs` 模块去⼲活。 >

关于 Electron 进程通信,我们要知道:

IPC 全称为: InterProcess Communication ,即:进程通信。

IPCElectron 中最为核⼼的内容,它是从 UI 调⽤原⽣ API 的唯⼀⽅法!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传Electron 中,主要使⽤ ipcMainipcRenderer 来定义“通道”,进⾏进程通信。

**10.1.** 渲染进程➡️主进程(单向)

概述:在$ {\color{red}渲染器进程} $中 [ipcRenderer.send](https://www.electronjs.org/zh/docs/latest/api/ipc-renderer) 发送消息,在$ {\color{red}主进程} $中使⽤ [ipcMain.on](https://www.electronjs.org/zh/docs/latest/api/ipc-main) 接收消息。常⽤于:$ {\color{red}在Web中调用主进程的API} $,例如下⾯的这个需求:

:::info
需求:点击按钮后,在⽤户的 D 盘创建⼀个 hello.txt ⽂件,⽂件内容来⾃于⽤户输⼊。

:::

  1. ⻚⾯中添加相关元素, render.js 中添加对应脚本

<input id="content" type="text"><br><br>
<button id="btn">在⽤户的D盘创建⼀个hello.txt</button>


const btn = document.getElementById('btn')
const content = document.getElementById('content')

btn.addEventListener('click',()=>{ 
    console.log(content.value) 	                  			    	 
    myAPI.saveFile(content.value)
})
  1. preload.js 中使⽤ ipcRenderer.send(‘信道’,参数) 发送消息,与主进程通信。

const {contextBridge,ipcRenderer} = require('electron') 

contextBridge.exposeInMainWorld('myAPI',{
    saveFile(str){
        // 渲染进程给主进程发送⼀个消息
        ipcRenderer.send('create-file',str)
    }
})
  1. 主进程中,在加载⻚⾯之前,使⽤ ipcMain.on(‘信道’,回调) 配置对应回调函数,接收消息。

// ⽤于创建窗⼝
function createWindow() {
    // 主进程注册对应回调
    ipcMain.on('create-file',createFile)
    // 加载⼀个本地⻚⾯
    win.loadFile(path.resolve(	dirname,'./pages/index.html'))
}

//创建⽂件
function createFile(event,data){ 
    fs.writeFileSync('D:/hello.txt',data)
}

**10.2.** 渲染进程↔主进程(双向)

概述:$ {\color{red}渲染进程} $通过[ipcRenderer.invoke](https://www.electronjs.org/zh/docs/latest/api/ipc-renderer#ipcrendererinvokechannel-args) 发送消息,$ {\color{red}主进程} $使⽤ [ipcMain.handle](https://www.electronjs.org/zh/docs/latest/api/ipc-main#ipcmainhandlechannel-listener) 接收并处理消息。

备注: ipcRender.invoke 的返回值是 Promise 实例。

常⽤于:从渲染器进程调用主进程方法并等待结果,例如下⾯的这个需求:

:::info
需求:点击按钮从 D 盘读取 hello.txt 中的内容,并将结果呈现在页面上。

:::

1. ⻚⾯中添加相关元素,<font style="color:rgb(37,37,37);">render.js</font> 中添加对应脚本

<button id="btn">读取⽤户D盘的hello.txt</button>
const btn = document.getElementById('btn') 

btn.addEventListener('click',async()=>{
  let data = await myAPI.readFile();
  document.body.innerHTML += `<h2>${data}</h2>`
})

2. <font style="color:rgb(37,37,37);">preload.js</font> 中使⽤ipcRenderer.invoke('信道',参数) 发送消息,与主进程通信。

const {contextBridge,ipcRenderer} = require('electron') 

contextBridge.exposeInMainWorld('myAPI',{
/*******/
  readFile (path){
    return ipcRenderer.invoke('read-file')
  }
})

3. 主进程中,在加载⻚⾯之前,使⽤ipcMain.handle('信道',回调) 接收消息,并配置回调函数。

// ⽤于创建窗⼝
function createWindow() {
  /**********/
  // 主进程注册对应回调
  ipcMain.handle('read-file',readFile)
  // 加载⼀个本地⻚⾯
  win.loadFile(path.resolve(	dirname,'./pages/index.html'))
}

//读取⽂件
function readFile(event,path){
  return fs.readFileSync(path).toString()
}

10.3. 主进程到➡渲染进程

概述: 主进程 使⽤ win.webContents.send 发送消息, 渲染进程 通过 ipcRenderer.on 处理消息,常⽤于:从主进程主动发送消息给渲染进程 ,例如下⾯的这个需求:

:::info
需求:应⽤加载 6 秒钟后,主动给渲染进程发送⼀个消息,内容是:你好啊!

:::

1. ⻚⾯中添加相关元素,render.js 中添加对应脚本

window.onload = ()=>{ 
  myAPI.getMessage(logMessage)
}

function logMessage(event,str){ 
  console.log(event,str)
}

2. <font style="color:rgb(37,37,37);">preload.js</font>中使⽤ipcRenderer.on ('信道',回调) 接收消息,并配置回调函数。

const {contextBridge,ipcRenderer} = require('electron') 
  
contextBridge.exposeInMainWorld('myAPI',{
/*******/
  getMessage: (callback) => {
    return ipcRenderer.on('message', callback);
  }
})

3. 主进程中,在合适的时候,使⽤win.webContents.send('信道',数据) 发送消息。

// ⽤于创建窗⼝
function createWindow() {
/**********/
  // 加载⼀个本地⻚⾯
  win.loadFile(path.resolve(	dirname,'./pages/index.html'))
  // 创建⼀个定时器
  setTimeout(() => { 
    win.webContents.send('message','你好啊!')
  }, 6000);
}

10.4. 渲染进程➡渲染进程

概述: 渲染进程A 使用 `ipcRenderer.send` 发送消息,在 主进程 中使用 `iocMain.on` 接收 渲染进程A 的消息。 主进程 接收到 渲染进程A 的消息后使用 `win.webContents.send` 向 渲染进程B 发送消息, 渲染进程B 使用 `ipcRenderer.on` 处理消息。例如,如下需求

上面的 win 为使用 const win = new BrowserWindow({...}) 创建 渲染进程B 返回的对象

:::info
需求:当前应用有两个窗口,indexA.htmlindexB.html indexA.html 中点击按钮将值传递给 indexB.html 并展示

:::

  1. indexA.html 中触发按钮
 <input type="text" id="name" name="name">
 <butto id='btn'> 同步 </butto>
const name = document.getElementById('name');
const btn = document.getElementById('btn');

btn.addEventListener('click',()=>{ 
    console.log(name.value) 	                  			    	 
    myAPI.saveName(name.value)
})
  1. preload.js 中使用 ipcRenderer.send() 发送消息,与 主进程 通信
const {contextBridge,ipcRenderer} = require('electron') 

contextBridge.exposeInMainWorld('myAPI',{
    saveName(str){
        // 渲染进程给主进程发送⼀个消息
        ipcRenderer.send('create-name',str)
    }
})
  1. 主进程 中,在加载 渲染进程A 之前,使⽤ ipcMain.on配置对应回调函数,接收消息。并且在配置的回调函数中,使用 win.webContents.send 向 渲染进程B 发送消息,传递数据
const { app, BrowserWindow } = require('electron')

let winB = new BrowserWindow({ 
    width: 800, // 窗⼝宽度 height: 600, // 窗⼝⾼度
    autoHideMenuBar: true, // ⾃动隐藏菜单栏
    alwaysOnTop: true, // 置顶
    x: 0, // 窗⼝位置x坐标
    y: 0 // 窗⼝位置y坐标
});
winB.loadFile('./pages/indexB.html');


let winA = new BrowserWindow({ 
    width: 800, // 窗⼝宽度 height: 600, // 窗⼝⾼度
    autoHideMenuBar: true, // ⾃动隐藏菜单栏
    alwaysOnTop: true, // 置顶
    x: 0, // 窗⼝位置x坐标
    y: 0 // 窗⼝位置y坐标
});
// 主进程注册对应回调
ipcMain.on('create-name',(event,data)=>{
  // 触发渲染进程B的监听事件
   winB.webContents.send('message',data)
})
winA.loadFile('./pages/indexA.html');

  1. preload.js 中使用 ipcRenderer.on 接收消息,并配置回调函数
const {contextBridge,ipcRenderer} = require('electron') 

contextBridge.exposeInMainWorld('myAPI',{
    saveName(str){
        // 渲染进程给主进程发送⼀个消息
        ipcRenderer.send('create-name',str)
    },
    getName(callback){
       return ipcRenderer.on('message', callback);
    },
})
  1. indexB.html 中接收消息,显示数据
window.onload = ()=>{ 
  myAPI.getName(logMessage)
}

function logMessage(event,str){ 
  console.log(event,str)
}

11. 打包应用

使⽤` electron-builder ` 打包应⽤

1. 安装 electron-builder :

npm install electron-builder -D

2. 在<font style="color:rgb(37,37,37);">package.json</font> 中进⾏相关配置,具体配置如下:

备注:json ⽂件不⽀持注释,使⽤时请去掉所有注释。

{
  "name": "video-tools",	// 应⽤程序的名称 
  "version": "1.0.0",		// 应⽤程序的版本 
  "main": "main.js",	// 应⽤程序的⼊⼝⽂件
  "scripts": {
    "start": "electron .",	// 使⽤ `electron .` 命令启动应⽤程序
    "build": "electron-builder" // 使⽤ `electron-builder` 打包应⽤程序,⽣成安装包
  },
  "build": {
    "appId": "com.atguigu.video",	// 应⽤程序的唯⼀标识符
    // 打包windows平台安装包的具体配置
    "win": {
      "icon":"./logo.ico", //应⽤图标 
      "target": [
        {
          "target": "nsis",	// 指定使⽤ NSIS 作为安装程序格式
          "arch": ["x64"]	// ⽣成 64 位安装包
        }
      ]
    },
    "nsis": {
      "oneClick": false,	// 设置为 `false` 使安装程序显示安装向导界⾯,⽽不是⼀键安装
      "perMachine": true,	// 允许每台机器安装⼀次,⽽不是每个⽤户都安装
      "allowToChangeInstallationDirectory": true // 允许⽤户在安装过程中选择安装⽬录
    }
  },
  "devDependencies": {
    "electron": "^30.0.0",	// 开发依赖中的 Electron 版本
    "electron-builder": "^24.13.3" // 开发依赖中的 `electron-builder` 版本
  },
  "author": "tianyu",	// 作者信息
  "license": "ISC",	// 许可证信息
  "description": "A video processing program based on Electron" // 应⽤程序的描述
}

3. 执⾏打包命令

npm run build

12. electron-vite

electron-vite 是 ⼀个新 型构 建⼯具,旨 在为 [Electron](https://www.electronjs.org/) 提 供更 快 、 更 精 简的体 验 。 主 要由 五 部 分 组 成 :

● ⼀套构建指令,它使⽤ Vite 打包你的代码,并且它能够处理 Electron 的独特环境,包括 Node.js 和浏览器环境。

● 集中配置主进程、渲染器和预加载脚本的Vite 配置,并针对Electron 的独特环境进⾏预配置。

● 为渲染器提供快速模块热替换(HMR)⽀持,为主进程和预加载脚本提供热重载⽀持,极⼤地提⾼了开发效率。

● 优化Electron 主进程资源处理。

● 使⽤ V8 字节码保护源代码。

electron-vite 快速、简单且功能强⼤,旨在开箱即⽤。官⽹地址:https://cn-evite.netlify.app/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值