文章目录
Electron 快速开始(一)-入门基础、使用 JavaScript,HTML 和 CSS 构建跨平台的桌面应用程序
Electron简介
Electron提供了丰富的本地(操作系统)的API,使你能够使用纯JavaScript来创建桌面应用程序。与其它各种的Node.js运行时不同的是Electron专注于桌面应用程序而不是Web服务器。
Electron是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 嵌入 Chromium 和 Node.js 到 二进制的 Electron 允许您保持一个 JavaScript 代码代码库并创建 在Windows上运行的跨平台应用 macOS和Linux——不需要本地开发 经验。
虽然B/S是目前开发的主流,但是C/S仍然有很大的市场需求。受限于浏览器的沙盒限制,网页应用无法满足某些场景下的使用需求,而桌面应用可以读写本地文件、调用更多系统资源,再加上Web开发的低成本、高效率的优势,这种方式越来越受到开发者的喜爱。
- Electron 基于 Chromium 和 Node.js, 让你可以使用 HTML, CSS 和 JavaScript 构建应用。
- Electron是一个由OpenJS基金会和一个活跃的贡献者社区管理的开源项目。
- Electron 兼容 Mac、Windows 和 Linux,可以构建出三个平台的应用程序。
使用Electron, 需要你有Node.js和web开发经验。
如果你可以建一个网站,你就可以建一个桌面应用程序。 Electron 是一个使用 JavaScript, HTML 和 CSS 等 Web 技术创建原生程序的框架,它负责比较难搞的部分,你只需把精力放在你的应用的核心上即可。
多进程模型
官方参考:https://www.electronjs.org/zh/docs/latest/tutorial/process-model
为了解决这个问题,Chrome 团队决定让每个标签页在自己的进程中渲染, 从而限制了一个网页上的有误或恶意代码可能导致的对整个应用程序造成的伤害。 然后用单个浏览器进程控制这些標籤頁进程,以及整个应用程序的生命周期。 下方来自 Chrome 漫画 的图表可视化了此模型:
Chrome的多进程架构
Electron 应用程序的结构非常相似。 作为应用开发者,您控制着两种类型的进程:主进程和渲染器。 这些类似于上面概述的 Chrome 自己的浏览器和其渲染器进程。
- 主进程
每个 Electron 应用都有一个单一的主进程,作为应用程序的入口点。 主进程在 Node.js 环境中运行,这意味着它具有 require 模块和使用所有 Node.js API 的能力。
窗口管理
主进程的主要目的是使用 BrowserWindow 模块创建和管理应用程序窗口。
BrowserWindow 类的每个实例创建一个应用程序窗口,且在单独的渲染器进程中加载一个网页。 您可从主进程用 window 的 webContent 对象与网页内容进行交互。
main.js
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ width: 800, height: 1500 })
win.loadURL('https://github.com')
const contents = win.webContents
console.log(contents)
注意:渲染器进程也是为 web embeds 而被创建的,例如 BrowserView 模块。 嵌入式网页内容也可访问 webContents 对象。
由于 BrowserWindow 模块是一个 EventEmitter, 所以您也可以为各种用户事件 ( 例如,最小化 或 最大化您的窗口 ) 添加处理程序。
当一个 BrowserWindow 实例被销毁时,与其相应的渲染器进程也会被终止。
应用程序生命周期
主进程还能通过 Electron 的 app 模块来控制您应用程序的生命周期。 该模块提供了一整套的事件和方法,可以使你添加自定义的应用程序行为 ( 例如:以编程方式退出您的应用程序、修改程序坞或显示关于面板 ) 。
这是一个实际的例子,这个app来源于快速入门指南,用 app API 创建了一个更原生的应用程序窗口体验。
// quitting the app when no windows are open on non-macOS platforms
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})
原生 API
为了使 Electron 的功能不仅仅限于对网页内容的封装,主进程也添加了自定义的 API 来与用户的作业系统进行交互。 Electron 有着多种控制原生桌面功能的模块,例如菜单、对话框以及托盘图标。
关于 Electron 主进程模块的完整列表,请参阅我们的 API 文档。
-
渲染器进程
每个 Electron 应用都会为每个打开的 BrowserWindow ( 与每个网页嵌入 ) 生成一个单独的渲染器进程。 洽如其名,渲染器负责 渲染 网页内容。 所以实际上,运行于渲染器进程中的代码是须遵照网页标准的 (至少就目前使用的 Chromium 而言是如此) -
预加载脚本
预加载(preload)脚本包含了那些执行于渲染器进程中,且先于网页内容开始加载的代码 。 这些脚本虽运行于渲染器的环境中,却因能访问 Node.js API 而拥有了更多的权限。
预加载脚本可以在 BrowserWindow 构造方法中的 webPreferences 选项里被附加到主进程。
const { BrowserWindow } = require('electron')
//...
const win = new BrowserWindow({
webPreferences: {
preload: 'path/to/preload.js'
}
})
//...
由于预加载脚本与渲染器共享同一个全局 Window 接口,并且可以访问 Node.js API,因此它通过在 window 全局中暴露任意您的网络内容可以随后使用的 API 来增强渲染器。
Electron 快速开始
官方参考:https://www.electronjs.org/zh/docs/latest/tutorial/quick-start
下面步骤完全参考官方 快速开始,官网快速开始非常完善,推荐阅读!
-
安装 node.js
Node.js官网:https://nodejs.org/zh-cn/,点击下载安装即可 -
检查node.js和npm是否安装成功
node -v
npm -v
建议把npm的仓库切换到国内taobao仓库,
注册cnpm命令,如下
npm install -g cnpm --registry=https://registry.npm.taobao.org
注意 因为 Electron 将 Node.js 嵌入到其二进制文件中,你应用运行时的 Node.js 版本与你系统中运行的 Node.js 版本无关。
- Electron的安装
mkdir my-electron-app && cd my-electron-app
npm init
init初始化命令会提示您在项目初始化配置中设置一些值 为本教程的目的,有几条规则需要遵循:
- entry point 应为 main.js.
author 与 description 可为任意值,但对于应用打包是必填项。
将 electron 包安装到应用的开发依赖中
npm install --save-dev electron
最后,您希望能够执行 Electron 如下所示,在您的 package.json配置文件中的scripts字段下增加一条start命令:
{
"scripts": {
"start": "electron ."
}
}
npm start
start命令能让您在开发模式下打开您的应用
注意:此脚本将告诉 Electron 在您项目根目录运行 此时,您的应用将立即抛出一个错误提示您它无法找到要运行的应用
运行主进程
任何 Electron 应用程序的入口都是 main 文件。 这个文件控制了主进程,它运行在一个完整的Node.js环境中,负责控制您应用的生命周期,显示原生界面,执行特殊操作并管理渲染器进程(稍后详细介绍)。
执行期间,Electron 将依据应用中 package.json配置下main字段中配置的值查找此文件,您应该已在应用脚手架步骤中配置。
要初始化这个main文件,需要在您项目的根目录下创建一个名为main.js的空文件。
注意:如果您此时再次运行start命令,您的应用将不再抛出任何错误! 然而,它不会做任何事因为我们还没有在main.js中添加任何代码。
此教程中,您将采用本地HTML的方式。 在您的项目根目录下创建一个名为index.html的文件:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<meta http-equiv="X-Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
We are using Node.js <span id="node-version"></span>,
Chromium <span id="chrome-version"></span>,
and Electron <span id="electron-version"></span>.
</body>
</html>
注意:在这个HTML文本中,您会发现主体文本中丢失了版本编号。 稍后我们将使用 JavaScript 动态插入它们。
在窗口中打开您的页面
现在您有了一个页面,将它加载进应用窗口中。 要做到这一点,你需要 两个Electron模块:
- app 模块,它控制应用程序的事件生命周期。
- BrowserWindow 模块,它创建和管理应用程序 窗口。
因为主进程运行着Node.js,您可以在文件头部将他们导入作为公共JS模块:
const { app, BrowserWindow } = require('electron')
然后,添加一个createWindow()方法来将index.html加载进一个新的BrowserWindow实例。
function createWindow () {
const win = new BrowserWindow({
width: 800,
height: 600
})
win.loadFile('index.html')
}
接着,调用createWindow()函数来打开您的窗口。
在 Electron 中,只有在 app 模块的 ready 事件被激发后才能创建浏览器窗口。 您可以通过使用 app.whenReady() API来监听此事件。 在whenReady()成功后调用createWindow()。
app.whenReady().then(() => {
createWindow()
})
注意:此时,您的电子应用程序应当成功 打开显示您页面的窗口!
如下图所示
管理窗口的生命周期
虽然你现在可以打开一个浏览器窗口,但你还需要一些额外的模板代码使其看起来更像是各平台原生的。 应用程序窗口在每个OS下有不同的行为,Electron将在app中实现这些约定的责任交给开发者们。
一般而言,你可以使用 进程 全局的 platform 属性来专门为某些操作系统运行代码。
关闭所有窗口时退出应用 (Windows & Linux)
在Windows和Linux上,关闭所有窗口通常会完全退出一个应用程序。
To implement this, listen for the app module’s ‘window-all-closed’ event, and call app.quit() if the user is not on macOS (darwin).
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})
通过预加载脚本从渲染器访问Node.js。
在主进程通过Node的全局 process 对象访问这个信息是微不足道的。 然而,你不能直接在主进程中编辑DOM,因为它无法访问渲染器 文档 上下文。 它们存在于完全不同的进程!
这是将 预加载 脚本连接到渲染器时派上用场的地方。 预加载脚本在渲染器进程加载之前加载,并有权访问两个 渲染器全局 (例如 window 和 document) 和 Node.js 环境。
创建一个名为 preload.js 的新脚本如下:
window.addEventListener('DOMContentLoaded', () => {
const replaceText = (selector, text) => {
const element = document.getElementById(selector)
if (element) element.innerText = text
}
for (const dependency of ['chrome', 'node', 'electron']) {
replaceText(`${dependency}-version`, process.versions[dependency])
}
})
上面的代码访问 Node.js process.versions 对象,并运行一个基本的 replaceText 辅助函数将版本号插入到 HTML 文档中。
要将此脚本附加到渲染器流程,请在你现有的 BrowserWindow 构造器中将路径中的预加载脚本传入 webPreferences.preload 选项。
// 在文件头部引入 Node.js 中的 path 模块
const path = require('path')
// 修改现有的 createWindow() 函数
function createWindow () {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
win.loadFile('index.html')
}
// ...
这里使用了两个Node.js概念:
- __dirname 字符串指向当前正在执行脚本的路径 (在本例中,它指向你的项目的根文件夹)。
- path.join API 将多个路径联结在一起,创建一个跨平台的路径字符串。
我们使用一个相对当前正在执行JavaScript文件的路径,这样您的相对路径将在开发模式和打包模式中都将有效。
额外:将功能添加到您的网页内容
此刻,您可能想知道如何为您的应用程序添加更多功能。
对于与您的网页内容的任何交互,您想要将脚本添加到您的渲染器进程中。 由于渲染器运行在正常的 Web 环境中,因此您可以在 index.html 文件关闭 标签之前添加一个
<script src="./renderer.js"></script>
然后,renderer.js 中包含的代码可以使用与典型前端开发相同的 JavaScript API 和工具,例如使用 webpack 来捆绑和缩小您的代码或使用 React 来管理您的用户界面。
总结我们所做的所有步骤:
-
我们启动了一个Node.js程序,并将Electron添加为依赖。
-
我们创建了一个 main.js 脚本来运行我们的主要进程,它控制我们的应用程序 并且在 Node.js 环境中运行。 在此脚本中, 我们使用 Electron 的 app 和 BrowserWindow 模块来创建一个浏览器窗口,在一个单独的进程(渲染器)中显示网页内容。
-
为了访问渲染器中的Node.js的某些功能,我们在 BrowserWindow 的构造函数上附加了一个预加载脚本。
打包并分发您的应用程序
最快捷的打包方式是使用 Electron Forge。
- 将 Electron Forge 添加到您应用的开发依赖中,并使用其"import"命令设置 Forge 的脚手架:
npm install --save-dev @electron-forge/cli
npx electron-forge import
✔ Checking your system
✔ Initializing Git Repository
✔ Writing modified package.json file
✔ Installing dependencies
✔ Writing modified package.json file
✔ Fixing .gitignore
We have ATTEMPTED to convert your app to be in a format that electron-forge understands.
Thanks for using "electron-forge"!!!
- 使用 Forge 的 make 命令来创建可分发的应用程序:
npm run make
> my-electron-app@1.0.0 make /my-electron-app
> electron-forge make
✔ Checking your system
✔ Resolving Forge Config
We need to package your application before we can make it
✔ Preparing to Package Application for arch: x64
✔ Preparing native dependencies
✔ Packaging Application
Making for the following targets: zip
✔ Making for target: zip - On platform: darwin - For arch: x64
Electron-forge 会创建 out 文件夹,您的软件包将在那里找到:
双击my-electron-app.exe,如下所示,