美文网首页
Electron 开发: 六千字完整教程

Electron 开发: 六千字完整教程

作者: you的日常 | 来源:发表于2022-01-08 15:45 被阅读0次

前言

本文包含打包自动更新简易API调试进程通信等相关知识点,内容较多,请酌情查看。

electron

简介

Electron 是由 Github 开发,是一个用 Html、css、JavaScript 来构建桌面应用程序的开源库,可以打包为 Mac、Windows、Linux 系统下的应用。

Electron 是一个运行时环境,包含 Node 和 Chromium,可以理解成把 web 应用运行在 node 环境中

结构

Electron 主要分为主进程和渲染进程,关系如下图


image.png

Electron 运行 package.json 中的 main 字段标明脚本的进程称为主进程

在主进程创建 web 页面来展示用户页面,一个 Electron 有且只有一个主进程

Electron 使用 Chromium 来展示 web 页面,每个页面运行在自己的渲染进程

快速开始

接下来,让代码来发声,雷打不动的 hello world

创建文件夹,并执行 npm init -y,生成 package.json 文件,下载 electron 模块并添加开发依赖

mkdir electron_hello && cd electron_hello && npm init -y && npm i electron -D

下载速度过慢或失败,请尝试使用cnpm,安装方式如下

# 下载cnpm
npm install -g cnpm --registry=https://registry.npm.taobao.org
# 下载electron
cnpm i electron -D

创建index.js,并写入以下内容

const {app, BrowserWindow} = require('electron')
// 创建全局变量并在下面引用,避免被GC
let win
function createWindow () {
    // 创建浏览器窗口并设置宽高
    win = new BrowserWindow({ width: 800, height: 600 })
    
    // 加载页面
    win.loadFile('./index.html')
    
    // 打开开发者工具
    win.webContents.openDevTools()
    
    // 添加window关闭触发事件
    
    win.on('closed', () => {
        win = null  // 取消引用
    })
}

// 初始化后 调用函数
app.on('ready', createWindow)  
// 当全部窗口关闭时退出。
app.on('window-all-closed', () => {
   // 在 macOS 上,除非用户用 Cmd + Q 确定地退出,
   // 否则绝大部分应用及其菜单栏会保持激活。
   if (process.platform !== 'darwin') {
        app.quit()
   }
})
  
app.on('activate', () => {
// 在macOS上,当单击dock图标并且没有其他窗口打开时,
// 通常在应用程序中重新创建一个窗口。
    if (win === null) {
      createWindow()
    }
})

创建index.html

<!DOCTYPE html>
<html>
    <head>
      <meta charset="UTF-8">
      <title>Hello World!</title>
    </head>
    <body>
        <h1 id="h1">Hello World!</h1>
        We are using node
        <script>
            document.write(process.versions.node)
        </script>
        Chrome
        <script>
            document.write(process.versions.chrome)
        </script>,
        and Electron
        <script>
            document.write(process.versions.electron)
        </script>
    </body>
</html>

最后,修改 packge.json 中的 main 字段,并添加 start 命令

{
    ...
    main:'index.js',
    scripts:{
        "start": "electron ."
    }
}

执行 npm run start 后,就会弹出我们的应用来。

image.png

调试

我们知道 Electron 有两个进程,主进程和渲染进程,开发过程中我们需要怎么去调试它们呢?老太太吃柿子,咱们捡软的来

渲染进程

BrowserWindow 用来创建和控制浏览器窗口,我们调用它的实例上的API即可

win = new BrowserWindow({width: 800, height: 600})
win.webContents.openDevTools() // 打开调试

调试起来是和 Chrome 是一样的,要不要这么酸爽

image.png

主进程

使用 VSCode 进行调试

使用 VSCode 打开项目,点击调试按钮


image.png

点击调试后的下拉框


image.png

选择添加配置,选择 node


image.png

此时会把默认的调试配置打开,大概长这样


image.png

什么?你的不是,不是的话,就直接把下面的复制并替换你的配置

差不多这么办,那就把 configurations 里面第二项复制到你的 configurations 配置里面,第一个配置是用来调试 node 的

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "启动程序",
      "program": "${workspaceFolder}/main.js"
    },
    {
        "name": "Debug Main Process",
        "type": "node",
        "request": "launch",
        "cwd": "${workspaceFolder}",
        "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
        "windows": {
          "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd"
        },
        "args" : ["."]
      }
  ]
}

可以看到 ${workspaceFolder},这是关于VSCode的变量,用来表示当前打开的文件夹的路径

修改完配置后,我们调试面板,选择我们刚才配置的


image.png

在代码中标记需要调试的地方,然后点击绿色的小三角,就可以愉快的调试了


image.png

进程通信

在 Electron 中, GUI 相关的模块 (如 dialog、menu 等) 仅在主进程中可用, 在渲染进程中不可用。 为了在渲染进程中使用它们, ipc 模块是向主进程发送进程间消息所必需的,以下介绍几种进程间通讯的方法。

哥俩好

ipcMain 和 ipcRenderer 是两个好基友,通过这两个模块可以实现进程的通信。

  • ipcMain 在主进程中使用,用来处理渲染进程(网页)发送的同步和异步的信息
  • ipcRenderer 在渲染进程中使用,用来发送同步或异步的信息给主进程,也可以用来接收主进程的回复信息。

以上两个模块的通信,可以理解成发布订阅模式,接下来,我们看下它们具体的使用方法

主进程

const {ipcMain} = require('electron')
// 监听渲染程序发来的事件
ipcMain.on('something', (event, data) => {
    event.sender.send('something1', '我是主进程返回的值')
})

渲染进程

const { ipcRenderer} = require('electron') 
// 发送事件给主进程
ipcRenderer.send('something', '传输给主进程的值')  
// 监听主进程发来的事件
ipcRenderer.on('something1', (event, data) => {
    console.log(data) // 我是主进程返回的值
})

以上代码使用的是异步传输消息,Electron 也提供了同步传输的 API。

发送同步消息将会阻塞整个渲染进程,你应该避免使用这种方式 - 除非你知道你在做什么。

切忌用 ipc 传递大量的数据,会有很大的性能问题,严重会让你整个应用卡住。

remote模块

使用 remote 模块, 你可以调用 main 进程对象的方法, 而不必显式发送进程间消息。

const { dialog } = require('electron').remote
dialog.showMessageBox({type: 'info', message: '在渲染进程中直接使用主进程的模块'})

webContents

webContents 负责渲染和控制网页, 是 BrowserWindow 对象的一个属性, 我们使用 send方法 向渲染器进程发送异步消息。

主进程

const {app, BrowserWindow} = require('electron')
let win
app.on('ready', () => {
    win = new BrowserWindow({width: 800, height: 600})
    
    // 加载页面
    win.loadURL('./index.html')
    
    // 导航完成时触发,即选项卡的旋转器将停止旋转,并指派onload事件后。
    win.webContents.on('did-finish-load', () => {
        // 发送数据给渲染程序
        win.webContents.send('something', '主进程发送到渲染进程的数据')
    })
})

渲染进程

<!DOCTYPE html>
<html>
    <head>
    </head>
    <body>
        <script>
            require('electron').ipcRenderer.on('something', (event, message) => {
                console.log(message) // 主进程发送到渲染进程的数据
            })
        </script>
    </body>
</html>

渲染进程数据共享

更多情况下,我们使用 HTML5 API 实现,如 localStorage、sessionStorage 等,也可以使用 Electron 的 IPC 机制实现

主进程

global.sharedObject = {
    someProperty: 'default value'
}

渲染进程

第一个页面

require('electron').remote.getGlobal('sharedObject').someProperty = 'new value'

第二个页面

console.log(require('electron').remote.getGlobal('sharedObject').someProperty) // new value

总结

以上四个方法均可实现主进程和渲染进程的通信,可以发现使用 remote 模块是最简单的,渲染进程代码中可以直接使用 electron 模块

常用模块

快捷键与菜单

本地快捷键

image.png

只有在应用聚焦的时候才会触发,主要代码如下

官方文档亲测没有效果

const { Menu, MenuItem } = require('electron')
const menu = new Menu()
  
menu.append(new MenuItem({
  label: '自定义快捷键',
  submenu: [
    {
      label: '测试',
      accelerator: 'CmdOrCtrl+P',
      click: () => { 
          console.log('我是本地快捷键')
      }
    }
  ]
}))
Menu.setApplicationMenu(menu)

全局快捷键

注册全局,无论应用是否聚焦,都会触发,使用 globalShortcut 来注册, 主要代码如下,

const {globalShortcut, dialog} = require('electron')
app.on('read', () => {
    globalShortcut.register('CmdOrCtrl+1', () => {
        dialog.showMessageBox({
            type: 'info',
            message: '你按下了全局注册的快捷键'
          })
    })
})

显示如下,使用了 dialog 模块

image.png

上下文菜单

上下文菜单就是我们点击右键的时候显示的菜单, 设置在渲染进程里面


image.png

主要代码如下

// 通过remote模块使用主程序才能使用的模块
const remote = require('electron').remote;  
const Menu = remote.Menu;
const MenuItem = remote.MenuItem;
var menu = new Menu();
menu.append(new MenuItem({ label: 'MenuItem1', click: function() { console.log('item 1 clicked'); } }));
menu.append(new MenuItem({ type: 'separator' }));
menu.append(new MenuItem({ label: 'MenuItem2', type: 'checkbox', checked: true }));
window.addEventListener('contextmenu', (e) => {
  e.preventDefault();
  menu.popup(remote.getCurrentWindow());
}, false);

应用菜单

相关文章

网友评论

      本文标题:Electron 开发: 六千字完整教程

      本文链接:https://www.haomeiwen.com/subject/adghqrtx.html