事实上的团队协作软件,Visual Studio Code - 在撰写本文时市场上最受欢迎的代码编辑器之一,以及WhatsApp的桌面版本都有一个共同点:它们都是用Electron构建的.js。随着这些强大的公司采用 Electron.js 而不是原生桌面软件开发方法,Electron.js 已将自己确立为开发桌面应用程序的值得信赖的框架。
在本教程中,您将了解 Electron.js 的全部内容以及如何使用它来推动您的下一个惊人想法。
在本教程结束时,您将开发一个桌面应用程序:
- 使用 Web 技术从头开始构建
- 在 Main 和 Renderer 进程之间进行通信
- 利用 Electron.js API 访问浏览器 API 中不可用的功能
- 显示桌面通知
项目要求
了解 Electron.js
简而言之,Electron.js 是一个开源框架,使开发人员能够使用 HTML、CSS 和 JavaScript 等 Web 技术构建桌面应用程序。有了这个,构建桌面应用程序不再是编写 C++、C# 或 Java 的开发人员的专有能力,因为 Web 开发人员现在可以将他们的技能转移到推出行业标准的桌面软件。
结合使用Chromium(Google Chrome 浏览器的开源版本)和Node.js JavaScript 运行时,Web 开发人员可以使用 Electron.js 包装现有的 Web 应用程序,以生成桌面应用程序并生成适用于Windows、macOS和Linux平台。
Electron.js 由Github维护,使其成为一个由强大的工程师团队支持的可靠项目。
为什么使用 Electron.js
在 Electron.js 之前,如果需要将应用程序安装在两个或多个不同的桌面操作系统(例如 Windows 和 Mac)上,您需要使用平台兼容的语言(即C#或Visual Basic for Windows )分别为这两个平台开发应用程序和用于 Mac的 Objective-C 。如果开发人员决定走Java路线(使用 Java 开发跨平台桌面软件),则此类应用程序的用户需要在两个平台上安装 Java 运行时才能运行该应用程序。
但是,使用单一代码库,Electron.js 可以为所有平台生成安装程序,而无需任何安装依赖。因此,单个开发团队可以为目标平台开发应用程序。另一个主要优势是,如果您可以构建网站,则可以使用 Electron.js 构建桌面应用程序,因此,现有的 Web 开发人员/Web 开发团队可以轻松地转化为桌面软件的开发人员。
构建 Electron.js 应用程序的先决条件
这些是开始使用 Electron.js 构建应用程序所需的东西:
- HTML、CSS 和 JavaScript 的基本知识
- 安装在您的系统上的Node.js
- Node.js 基础知识
Electron.js 应用程序的结构
Electron.js 应用程序的结构
在结构上,Electron.js 由三个主要部分组成:
- Chromium:这是 Electron.js 结构中负责创建和显示网页的组件。Web 内容显示在 Electron.js 的 Renderer 进程中(稍后会详细介绍),并且由于 Chromium 环境,您可以访问所有浏览器 API 和开发工具,就像在典型的 Google Chrome 浏览器中操作一样。
- Node.js:这是 Electron.js 结构中的组件,可让您访问系统功能。Electron.js 在其主进程中运行 Node.js(稍后会详细介绍),让您可以访问 Node.js 提供的所有内容,例如与文件系统、操作系统等交互等等......
- 自定义 API:为了使开发人员能够创建常见的桌面体验并轻松使用本机功能,Electron.js 有一个易于使用的库 API,可帮助您执行创建和显示上下文菜单、显示桌面通知、使用键盘快捷键等任务, ETC。
主进程和渲染器进程
运行中的 Electron.js 应用程序维护两种类型的进程,主进程和一个或多个渲染器进程。
Electron.js 应用程序的入口点是 Main 进程,它只是一个 Node.js 环境。这是与本机功能进行所有交互的地方。
主进程负责创建网页。它通过创建 Electron.js BrowserWindow
对象的新实例来实现这一点。这将创建一个在其自己的渲染器进程中运行的新网页。Main 进程可以创建多个网页,每个网页都在自己的 Renderer 进程中运行。
通常,Electron.js 应用程序使用默认网页启动,该网页是应用程序的启动屏幕。然后,如果您的应用程序需要,您可以创建更多屏幕。
每个 Renderer 进程管理自己的网页,并与其他 Renderer 进程和 Main 进程本身完全隔离。因此,如果一个 Renderer 进程终止,它不会影响另一个 Renderer 进程。渲染器进程也可以通过销毁其BrowserWindow
实例从主进程中终止。
开箱即用,Renderer 进程只能访问浏览器 API,如window
和document
对象等。这是因为 Renderer 进程只是一个正在运行的 Chromium 浏览器实例。但是,它可以配置为访问 Node.js API,例如process
和require
.
主进程和渲染器进程之间的通信
通常,您会希望在 Electron.js 应用程序中使用本机功能来响应事件,例如用户单击按钮。但是,由于 Renderer 进程和 Main 进程完全相互隔离,因此无法直接从网页访问原生功能。
为了实现这一点,Electron.js 提供了一个IPC (进程间通信)通道,允许渲染器进程与主进程通信,反之亦然。
分别对 Main 进程和 Renderer 进程使用ipcMain
和ipcRenderer
模块,您可以从一个进程发出事件并侦听另一个进程中的事件。您还可以将数据从一个进程传递到另一个进程。在本教程后面完成的练习中,您将使用这些模块在渲染器和主进程之间进行通信。
构建一个简单的 Electron.js 项目
现在是时候进行一些编码并获得一些动手 Electron.js 的经验了!在本教程中,您将创建一个简单的桌面应用程序,将项目添加到任务列表中。目标是从头开始创建桌面应用程序并成功运行。
脚手架应用程序
首先,从您的首选父目录运行以下命令为项目创建一个文件夹,然后将目录更改为新文件夹:
mkdir my-electron-appcd my-electron-app
因为 Electron.js 应用程序本质上是一个运行网页的 Node.js 应用程序,所以您需要初始化应用程序并通过运行以下命令创建一个package.json文件:
npm init -y
接下来,通过在项目文件夹的根目录创建index.html文件来创建应用程序主页,并添加以下代码:
<!DOCTYPE html>
<html LANG="EN">
<head>
<meta CHARSET="UTF-8">
<meta name="VIEWPORT" content="width=device-width, initial-scale=1.0">
<title>My Electron App</title>
</head>
<body>
<h1>Welcome to My Electron App</h1>
</body>
</html>
上面的 HTML 代码创建了一个简单的网页,其标题为“My Electron App”,h1
正文中的标签为“Welcome to My Electron App”。
至此,您拥有了一个基本的 Node.js 应用程序。下一步是使用 Electron.js 将您的应用程序转换为桌面应用程序。
首先安装 Electron.js 库。返回命令提示符,仍然在项目的根目录中,运行以下命令:
npm install --save-dev electron
安装完成后,创建一个名为main.js的新文件。这将是应用程序的入口点:它是主进程脚本。该脚本将执行以下操作:
- 为应用程序主屏幕创建网页
- 启动 Electron.js 应用程序时加载应用程序主屏幕
- 如果应用程序的窗口已关闭但应用程序仍在运行,则在单击应用程序图标时加载主屏幕
在您的新文件main.js 中,首先导入必要的包,然后创建一个函数,该函数的任务是为应用程序主屏幕创建一个新网页:
const { app, BrowserWindow } = require("electron");
const path = require("path");
const loadMainWindow = () => {
const mainWindow = new BrowserWindow({
width : 1200,
height: 800,
webPreferences: {
nodeIntegration: true
}
});
mainWindow.loadFile(path.join(__dirname, "index.html"));
}
在上面的代码块中,app
(Electron.js 应用程序对象)和BrowserWindow
(用于创建和加载网页的 Electron.js 模块)是从 Electron.js 包中导入的。该path
模块也被导入,使您能够使用项目目录。
导入后,创建loadMainWindow()
函数。此函数使用该BrowserWindow
对象创建一个新的 1200 像素 x 800 像素的浏览器窗口,该窗口从项目的根目录加载index.html文件。
接下来,在现有代码下方,添加对该loadMainWindow()
函数的调用,以便在应用启动后立即调用该函数:
app.on("ready", loadMainWindow);
loadMainWindow()
唯一在应用程序上发出事件时被调用ready
。网页需要等待这个事件,因为有些API只有在这个事件发生后才能使用。
下一步是解决某些操作系统上的问题,即使在所有窗口都关闭后,应用程序仍然保持活动状态。这通常发生在非 MacOS 平台上。要解决此问题,请在main.js中的现有代码下方添加以下内容:
app.on("window-all-closed", () => {
if (process.platform !== "darwin") {
app.quit();
}
});
此代码指示应用程序侦听window-all-closed
事件,该事件在主进程创建的所有窗口都已关闭时触发。然后它检查平台是否是 MacOS,如果不是,它显式退出应用程序,结束主进程,从而终止应用程序。
此文件中的最后一步是确保在没有打开任何窗口时在操作系统的应用程序停靠栏中单击其图标时启动应用程序。为此,请在文件末尾添加以下代码:
app.on("activate", () => {
if (BrowserWindow.getAllWindows().length === 0) {
loadMainWindow();
}
});
此代码侦听activate
应用程序上的事件。发出事件时,此代码会检查当前是否打开了属于应用程序的任何窗口。如果没有,则通过调用加载主屏幕loadMainWindow()
。
main.js文件就是这样。
配置应用程序
您需要对package.json文件进行一些更改,以确保它已正确配置以与 Electrion.js 一起使用。
打开你的package.json文件。main
将key的值改为main.js
如下图:
"main": "main.js"
接下来,将start
脚本添加到如下scripts
部分:
"scripts": {
"start" : "electron .",
"test": "echo \"Error: no test specified\" && exit 1"
}
保存并关闭文件。此时,您可以使用以下命令运行新的 Electron.js 应用程序:
npm start
这将启动应用程序并加载主屏幕。
创建一个简单的任务列表系统
为了学习 Electrion.js 的一些其他特性,您将创建一个简单的任务列表系统。
首先,您将向应用的主屏幕添加一些基本内容。
打开index.html文件并在该部分的标签下方添加Bootstrap库,如下所示:meta
head
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<title>My Electron App</title>
</head>
接下来,在body
元素内部,标签下方h1
,添加突出显示的行以创建两列布局。第一列将包含任务列表:
<body>
<h1>Welcome to My Electron App</h1>
<div class="container">
<div class="row">
<div class="col-md-6">
<ul id="list" class="list-group">
<li class="list-group-item">Buy Groceries</li>
<li class="list-group-item">Cook Meal</li>
</ul>
</div>
<div class="col-md-6">
</div>
</div>
</div>
</body>
Ctrl+C
如果应用程序当前正在运行,请在命令提示符下按关闭它,然后通过运行重新启动它npm start
。您将看到以下屏幕:
使用 Electron.js API 显示桌面通知
在本节中,您将创建将新项目添加到任务列表的功能,然后在添加新项目时显示通知。本节的目的是演示渲染器和主进程之间的通信。
将新项目添加到任务列表
在您的 index.html 文件中,添加一个表单输入和按钮元素。用户将与这些元素交互以将新项目添加到任务列表中。要添加这些元素,请将突出显示的行复制并粘贴到双列网格的第二列中:
<body>
<h1>Welcome to My Electron App</h1>
<div class="container">
<div class="row">
<div class="col-md-6">
<ul id="list" class="list-group">
<li class="list-group-item">Buy Groceries</li>
<li class="list-group-item">Cook Meal</li>
</ul>
</div>
<div class="col-md-6">
<input class="form-control" id="newTask" placeholder="Enter New Task" />
<br />
<button type="button" class="btn btn-primary" id="addTask">
Add Task
</button>
</div>
</div>
</div>
</body>
现在,在项目的根目录创建一个名为script.js的新 JavaScript 文件,并将其导入index.html文件,如下所示:
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<script src="script.js"></script>
<title>My Electron App</title>
</head>
在script.js文件中,添加以下代码:
let list = document.getElementById("list");
let newTask = document.getElementById("newTask");
document.getElementById("addTask").addEventListener('click', () => {
list.insertAdjacentHTML('beforeend', `<li class="list-group-item">${newTask.value}</li>`)
newTask.value = '';
});
在上面的代码中,click
事件处理程序被添加到您在index.htmlbutton
中添加的元素中。单击按钮时,输入字段的值将插入到新的<li> 元素中,该元素将附加到任务列表中。
现在,退出应用程序并重新启动。尝试通过在输入字段中键入并单击“添加任务”按钮来添加一些新项目。
显示新添加项目的通知
您将添加到应用程序的最后一个功能是桌面通知。每次将新项目添加到列表时都会显示通知。尽管 Electron.js 可以使用渲染器进程中的HTML 5 通知 API创建通知,但您将使用仅在主进程中可用的 Electron.js 通知模块。因此,Renderer 进程将需要与 Main 进程通信以使通知工作。
为此,我们将使用ipcRenderer
和ipcMain
模块。该ipcRenderer
在此处用于使用show-notification向主进程ipcMain
发送事件。重构script.js文件以反映下面突出显示的更改:show-notification
task
const { ipcRenderer } = require('electron');
let list = document.getElementById("list");
let newTask = document.getElementById("newTask");
document.getElementById("addTask").addEventListener('click', () => {
list.insertAdjacentHTML('beforeend', `<li class="list-group-item">${newTask.value}</li>`);
ipcRenderer.invoke('show-notification', newTask.value);
newTask.value = '';
});
我们可以require
在 Renderer 进程中访问,因为我们nodeIntegration: true
在main.js中进行了设置。这使我们能够访问 Node.js API。
主进程需要通过显示新任务的通知来响应此事件。
首先,将main.js中的第一行更改为以下内容:
const { app, BrowserWindow, ipcMain, Notification } = require("electron");
这添加了来自 Electron.js 包的ipcMain
和模块的导入。接下来,在main.js Notification
中的所有现有代码下方,添加以下内容:
ipcMain.handle('show-notification', (event, ...args) => {
const notification = {
title: 'New Task',
body: `Added: ${args[0]}`
}
new Notification(notification).show()
});
上面的代码ipcMain
用于侦听show-notification
从 Renderer 进程发送的事件以创建通知并显示它。
测试
要测试到目前为止编写的所有代码,请退出应用程序并重新启动它。应用程序加载成功后,添加一个新的任务项。您将在屏幕右上角看到一个通知弹出窗口,如下所示:
在 macOS(通常还有其他一些操作系统)上,您可能会收到提示,要求您批准从应用程序显示通知的权限。批准此请求以允许显示通知。
结论
Electron.js 是应用程序开发领域的游戏规则改变者,因为它为 Web 开发人员提供了巨大的力量,让他们能够利用他们现有的技能集进入原生应用程序开发领域。