Electron入门

Electron介绍

  • 一款应用广泛的跨平台桌面应用开发框架
  • Electron的本质是结合了Chromium与Node.js
  • 使用HTML,CSS,JS等Web技术构建桌面应用程序
    20240625111122

还有原生api的事


Electron流程模型
20240625112028

node环境的主进程

渲染进程通过IPC通信进行进程通信

比如要实现窗口选择文件,那么渲染进程是无法选择的,但是可以让主进程去选择

创建Electron项目

直接 npm i electron -D先安装

如果因为网络文件安装不上,可以手动指定安装源

npm install electron --electron_mirror=https://cdn.npmmirror.com/binaries/electron/

其中package.json配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"name": "electron_test",
"version": "1.0.0",
"main": "main.js",
"scripts": {
"start": "electron .",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "ZZMR",
"license": "ISC",
"description": "electron_study",
"dependencies": {
"electron": "^39.2.7"
}
}

如果想实现热刷新
启动配置文件中
"start": "nodemon --exec electron .",
使用nodemon来启动应用

BrowerWindow配置项

https://www.electronjs.org/zh/docs/latest/api/structures/base-window-options

进程通信

主进程->预加载脚本->渲染进程
而预加载脚本是运行在渲染进程上的

主进程和渲染进程之间的通信需要走预加载脚本

20260101154534

但实际上预加载脚本是运行在渲染进程中的,从这里预加载脚本输出位置就可以看出来

渲染进程->主进程

很简单

  1. 在预加载脚本中声明一个方法
    1
    2
    3
    4
    5
    6
    7
    8
    contextBridge.exposeInMainWorld('myApi', {
    nodeVersion: process.version,
    // 这个方法就是用来通信的方法
    saveFile: (data) => {
    ipcRenderer.send('file-save', data)
    // alert('get data from render process: ' + data)
    }
    })
  2. 在渲染进程中调用这个方法
    1
    2
    3
    btn2.onclick = () => {
    myApi.saveFile(input1.value)
    }
  3. 在主进程中订阅这个方法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    function writeFile(event, data) {
    // 如果文件不存在,会自动创建文件,但是并不会自动创建目录
    fs.writeFileSync('C:/CodeRepo/Electron/output/hello.txt', data)
    }

    const createWindow = () => {
    const win = new BrowserWindow({
    width: 800,
    height: 600,
    autoHideMenuBar: true,
    webPreferences:{
    preload: path.resolve(__dirname, './preload.js')
    }
    })

    // load this blog
    // win.loadURL('https://blog.zzmr.art')

    ipcMain.on('file-save', writeFile)
    win.loadFile('pages/index.html')
    }

双向通信

  1. 同样是预加载脚本中定义方法,但是注意,这里要接返回值,同时是使用invoke来传递的方法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    contextBridge.exposeInMainWorld('myApi', {
    nodeVersion: process.version,
    saveFile: (data) => {
    ipcRenderer.send('file-save', data)
    // alert('get data from render process: ' + data)
    },
    readFile: () => {
    // 也可以传参,响应结果是一个promise
    // let x = ipcRenderer.invoke('file-read')
    return ipcRenderer.invoke('file-read')
    }
    })
  2. 渲染进程中调用,获取主进程通过预加载脚本传递的返回值
    1
    2
    3
    btn3.onclick = async () => {
    input2.value = await myApi.readFile()
    }
  3. 主进程中订阅,但是这里的订阅是用的handle
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    function readFile() {
    const str = fs.readFileSync('C:/CodeRepo/Electron/output/hello.txt').toString()
    console.log('read file content: ', str)
    return str
    }

    const createWindow = () => {
    const win = new BrowserWindow({
    width: 800,
    height: 600,
    autoHideMenuBar: true,
    webPreferences:{
    preload: path.resolve(__dirname, './preload.js')
    }
    })

    // load this blog
    // win.loadURL('https://blog.zzmr.art')

    ipcMain.on('file-save', writeFile)
    ipcMain.handle('file-read', readFile)
    win.loadFile('pages/index.html')
    }

打包应用

首先要安装打包配置
npm install electron-builder -D

打包时,要把package.json中的electron配置给删掉,不然会报错
Package "electron" is only allowed in "devDependencies". Please remove it from the "dependencies" section in your package.json.

1
2
3
"dependencies": {
"electron": "^39.2.7"
},

打包时因为各种网络问题导致下载不了github上的文件时,可以直接去下载然后放到cache文件夹下
20260101171509
20260101171521