使用 Electron.JS 构建原生桌面应用程序

2025-06-08

使用 Electron.JS 构建原生桌面应用程序

JavaScript 被浏览器束缚的时代已经一去不复返了。Electron,或者说 Electron.js,是由 OpenJS 基金会维护的一个框架,用于使用 JavaScript、HTML 和 CSS 等 Web 技术构建原生桌面应用程序。

越来越多的原生应用程序,如 Spotify、VSCode 和 Slack,都是使用 Electron 构建的!

这个开源框架使用 Chromium 和 Node.js,可用于创建兼容 Windows、Mac 和 Linux 的跨平台应用程序。在本文中,我们将使用 Electron 构建一个可以在本地运行的简单井字游戏。


Electron 基础知识

Electron 由三个主要组件组成:

  • 处理所有网络内容的 Chromium
  • 处理与操作系统交互的 Node.js
  • 自定义 API,用于附加功能并解决处理操作系统时的常见问题

所有这些组件协同工作以促进桌面应用程序的实现。

此外,Electron 包含两个主要进程。主进程负责窗口管理、所有操作系统交互,渲染进程负责 Web 内容。

渲染进程无法直接与操作系统交互,只能通过主进程进行通信。根据应用程序的不同,一个主进程可以有多个渲染进程。不过,大多数情况下,会使用一个主进程和一个渲染器进程来加载 Web 应用程序。

解释清楚之后,我们就开始构建吧。


设置我们的项目

要使用 Electron,你需要在你的环境中安装 Node.js。我们可以先运行以下命令创建 npm 项目:

npm init

设置好项目后,我们可以使用以下命令安装 Electron:

npm i -D electron@latest

创建 Electron 应用
在我们的 Electron 应用中,我们将使用一个简单的 HTML 页面来运行一场乒乓球游戏。这样,我们只需要关注应用的 Electron 部分,而不是游戏本身。

几周前,我们只用 100 行代码就制作了 Pong,所以我们将重复使用该项目

我们将在项目文件夹中创建两个文件。index.js 将充当我们的主要节点进程,而 pong.html 将充当渲染器进程来加载天气数据。

// Include Electron
const { app, BrowserWindow } = require('electron');
// Create the main window for the application
function createMainWindow () {
// Setup the windows options
const win = new BrowserWindow({
width: 800,
height: 800,
webPreferences: {
nodeIntegration: true
}
});
// load the html file
win.loadFile('pong.html');
// Open DevTools - For Debugging (Optional)
// win.webContents.openDevTools()
}
app.whenReady().then(createMainWindow);
// Close the application when all windows are closed
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
});
// When the application is activated create the main window if not exists
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createMainWindow()
}
});
view raw index.js hosted with ❤ by GitHub
// Include Electron
const { app, BrowserWindow } = require('electron');
// Create the main window for the application
function createMainWindow () {
// Setup the windows options
const win = new BrowserWindow({
width: 800,
height: 800,
webPreferences: {
nodeIntegration: true
}
});
// load the html file
win.loadFile('pong.html');
// Open DevTools - For Debugging (Optional)
// win.webContents.openDevTools()
}
app.whenReady().then(createMainWindow);
// Close the application when all windows are closed
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
});
// When the application is activated create the main window if not exists
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createMainWindow()
}
});
view raw index.js hosted with ❤ by GitHub

index.js 文件将帮助应用程序创建窗口并加载相应的渲染进程。在本例中,我们的 pong.html 文件如下所示:

<!-- Pull in P5.JS graphics library -->
<script
src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.min.js"
integrity="sha512-WIklPM6qPCIp6d3fSSr90j+1unQHUOoWDS4sdTiR8gxUTnyZ8S2Mr8e10sKKJ/bhJgpAa/qG068RDkg6fIlNFA=="
crossorigin="anonymous"
></script>
<script>
const screenDim = 500;
let score = [0, 0];
let ball = { x: 250, y: 100, vx: 2, vy: 2 };
let play1 = { x: 30, y: 250, height: 100, width: 20 };
let play2 = { x: screenDim - 50, y: 250, height: 100, width: 20 };
function setup() { // Runs on startup
frameRate(100);
createCanvas(screenDim, screenDim);
}
function draw() { // Runs on loop according to frameRate
fill("transparent");
rect(0, 0, screenDim, screenDim); // Draw the box around our game
// Show Score
fill("black");
textSize(32);
text(score[0] + " - " + score[1], screenDim / 2 - 40, 100);
// Draw ball
fill("red");
ellipse(ball.x, ball.y, 10, 10);
// Draw paddles
fill("black");
rect(play1.x, play1.y, play1.width, play1.height);
rect(play2.x, play2.y, play2.width, play2.height);
if (ball.y > screenDim - 10 || ball.y < 10) { // Bounce off top and bottom
ball.vy *= -1;
}
if ( // If intersecting with Paddle #1
ball.x < play1.x + play1.width + 10 &&
ball.y > play1.y &&
ball.y < play1.y + play1.height
) {
ball.vx *= -1.1; // Invert and increase velocity by 10%
ball.vy = random(8) - 4; // Random y velocity between -4 and 4
}
if ( // If intersecting with Paddle #2
ball.x > play2.x - 10 && // If it
ball.y > play2.y &&
ball.y < play2.y + play2.height
) {
ball.vx *= -1.1; // Invert and increase velocity by 10%
ball.vy = random(8) - 4; // Random y velocity between -4 and 4
}
// Move Paddles
if (keyIsDown(87) && play1.y > 5) { // W is pressed
play1.y -= 4;
}
if (keyIsDown(83) && play1.y < screenDim - play1.height) { // S is pressed
play1.y += 4;
}
if (keyIsDown(UP_ARROW) && play2.y > 5) {
play2.y -= 4;
}
if (keyIsDown(DOWN_ARROW) && play2.y < screenDim - play1.height) {
play2.y += 4;
}
// Update score
if (ball.x < 0) {
score[1] += 1;
ball = { x: 250, y: 100, vx: 2, vy: 2 };
}
if (ball.x > screenDim) {
score[0] += 1;
ball = { x: 250, y: 100, vx: -2, vy: 2 };
}
// Move the ball
ball.x += ball.vx;
ball.y += ball.vy;
}
</script>
view raw pong.html hosted with ❤ by GitHub
<!-- Pull in P5.JS graphics library -->
<script
src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.min.js"
integrity="sha512-WIklPM6qPCIp6d3fSSr90j+1unQHUOoWDS4sdTiR8gxUTnyZ8S2Mr8e10sKKJ/bhJgpAa/qG068RDkg6fIlNFA=="
crossorigin="anonymous"
></script>
<script>
const screenDim = 500;
let score = [0, 0];
let ball = { x: 250, y: 100, vx: 2, vy: 2 };
let play1 = { x: 30, y: 250, height: 100, width: 20 };
let play2 = { x: screenDim - 50, y: 250, height: 100, width: 20 };
function setup() { // Runs on startup
frameRate(100);
createCanvas(screenDim, screenDim);
}
function draw() { // Runs on loop according to frameRate
fill("transparent");
rect(0, 0, screenDim, screenDim); // Draw the box around our game
// Show Score
fill("black");
textSize(32);
text(score[0] + " - " + score[1], screenDim / 2 - 40, 100);
// Draw ball
fill("red");
ellipse(ball.x, ball.y, 10, 10);
// Draw paddles
fill("black");
rect(play1.x, play1.y, play1.width, play1.height);
rect(play2.x, play2.y, play2.width, play2.height);
if (ball.y > screenDim - 10 || ball.y < 10) { // Bounce off top and bottom
ball.vy *= -1;
}
if ( // If intersecting with Paddle #1
ball.x < play1.x + play1.width + 10 &&
ball.y > play1.y &&
ball.y < play1.y + play1.height
) {
ball.vx *= -1.1; // Invert and increase velocity by 10%
ball.vy = random(8) - 4; // Random y velocity between -4 and 4
}
if ( // If intersecting with Paddle #2
ball.x > play2.x - 10 && // If it
ball.y > play2.y &&
ball.y < play2.y + play2.height
) {
ball.vx *= -1.1; // Invert and increase velocity by 10%
ball.vy = random(8) - 4; // Random y velocity between -4 and 4
}
// Move Paddles
if (keyIsDown(87) && play1.y > 5) { // W is pressed
play1.y -= 4;
}
if (keyIsDown(83) && play1.y < screenDim - play1.height) { // S is pressed
play1.y += 4;
}
if (keyIsDown(UP_ARROW) && play2.y > 5) {
play2.y -= 4;
}
if (keyIsDown(DOWN_ARROW) && play2.y < screenDim - play1.height) {
play2.y += 4;
}
// Update score
if (ball.x < 0) {
score[1] += 1;
ball = { x: 250, y: 100, vx: 2, vy: 2 };
}
if (ball.x > screenDim) {
score[0] += 1;
ball = { x: 250, y: 100, vx: -2, vy: 2 };
}
// Move the ball
ball.x += ball.vx;
ball.y += ball.vy;
}
</script>
view raw pong.html hosted with ❤ by GitHub

我们现在可以使用以下命令在本地运行我们的应用程序:

electron index.js

图片描述

就这样!我们的 html 文件已经原生运行了!


结论

Electron 日益流行,使其成为有抱负的开发者必学的语言。更何况,如果你是一名 Web 开发者,想要快速创建网站的原生版本,Electron 可能是最佳选择。

如果您正在构建软件并希望消除瓶颈,那么Codesphere就是您的云服务需求的最佳选择!我们正在将 Codesphere 打造为市场上最直观的云和 DevOps 工具!

编码愉快!

鏂囩珷鏉ユ簮锛�https://dev.to/codesphere/building-native-desktop-apps-with-electronjs-4m8n
PREV
Jamstack 入门
NEXT
推销自己作为开发者的 5 种最有效方法