Home >> Blog >> 如何使用 Electron 建立桌面應用程式

如何使用 Electron 建立桌面應用程式

Slack - 有名的SEO搜尋引擎優化團隊合作軟體,Visual Studio Code - 在撰寫本文時市場上最受歡迎的程式碼編輯器之一,以及WhatsApp的桌面版本都有一個共同點:它們都是用Electron構建的.js。隨著這些強大的公司採用 Electron.js 而不是原生桌面軟體開發方法,Electron.js 已將自己確立為開發桌面應用程式的值得信賴的框架。

在本教學中,您將了解 Electron.js 的全部內容以及如何使用它來推動您的下一個驚人想法。

在本教學結束時,您將開發一個桌面應用程式:

項目要求

了解 Electron.js

簡而言之,Electron.js 是一個開源框架,使開發人員能夠使用 HTML、CSS 和 JavaScript 等 Web 技術構建桌面應用程式。有了這個,構建桌面應用程式不再是編寫 C++、C# 或 Java 的開發人員的專有能力,因為 Web 開發人員現在可以將他們的技能轉移到推出行業標準的桌面軟體。

結合使用Chromium(谷歌 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 構建應用程式所需的東西:

Electron.js 應用程式的結構

Electron.js 應用程式的結構

使用 Electron 構建桌面應用程式的介紹

在結構上,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 應用程式維護兩種類型的進程,主進程和一個或多個R渲染器進程。

Electron.js 應用程式的入口點是 Main 進程,它只是一個 Node.js 環境。這是與本機功能進行所有交互的地方。

主進程負責創建網頁。它通過創建 Electron.jsBrowserWindow對象的新實例來實現這一點。這將創建一個在其自己的渲染器進程中運行的新網頁。Main 進程可以創建多個網頁,每個網頁都在自己的 Renderer 進程中運行。

通常,Electron.js 應用程式使用默認網頁啟動,該網頁是應用程式的啟動螢幕。然後,如果您的應用程式需要,您可以創建更多螢幕。

每個 Renderer 進程管理自己的網頁,並與其他 Renderer 進程和 Main 進程本身完全隔離。因此,如果一個 Renderer 進程終止,它不會影響另一個 Renderer 進程。渲染器進程也可以通過銷毀其BrowserWindow實例從主進程中終止。

開箱即用,Renderer 進程只能訪問瀏覽器 API,如window和document對像等。這是因為 Renderer 進程只是一個正在運行的 Chromium 瀏覽器實例。但是,它可以配置為訪問 Node.js API,例如process和require.

使用 Electron 構建桌面應用程式的介紹

主進程和渲染器進程之間的通信

通常,您會希望在 Electron.js 應用程式中使用本機功能來響應事件,例如用戶單擊按鈕。但是,由於 Renderer 進程和 Main 進程完全相互隔離,因此無法直接從網頁訪問原生功能。

為了實現這一點,Electron.js 提供了一個IPC (進程間通信)通道,允許渲染器進程與主進程通信,反之亦然。

分別對 Main 進程和 Renderer 進程使用ipcMain和ipcRenderer模塊,您可以從一個進程發出事件並偵聽另一個進程中的事件。您還可以將數據從一個進程傳遞到另一個進程。在本教學後面完成的練習中,您將使用這些模塊在渲染器和主進程之間進行通信。

構建一個簡單的 Electron.js 項目

現在是時候進行一些編碼並獲得一些動手 Electron.js 的經驗了!在本教學中,您將創建一個簡單的桌面應用程式,將項目添加到任務列表中。目標是從頭開始創建一個桌面應用程式並成功運行它。

腳手架應用程式

首先,從您的首選父目錄運行以下命令為項目創建一個文件夾,然後將目錄更改為新文件夾:

mkdir my-electron-app
cd 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
< /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);

下一步是解決某些操作系統上的問題,即使在所有窗口都關閉後,應用程式仍然保持活動狀態。這通常發生在非 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庫,如下所示:metahead

< 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 class="list-group-item">Cook Meal
< /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
< 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 class="list-group-item">Cook Meal
< /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}`)
newTask.value = '';
});

在上面的程式碼中,一個click事件處理程式被添加到您在index.htmlbutton中添加的元素中。單擊按鈕時,輸入字段的值將插入到新的> 元素中,該元素將附加到任務列表中。

現在,退出應用程式並重新啟動。嘗試通過在輸入字段中鍵入並單擊“添加任務”按鈕來添加一些新項目。

顯示新添加項目的通知

您將添加到應用程式的最後一個功能是桌面通知。每次將新項目添加到列表時都會顯示通知。儘管 Electron.js 可以使用渲染器進程中的HTML 5 通知 API創建通知,但您將使用僅在主進程中可用的 Electron.js 通知模塊。因此,Renderer 進程將需要與 Main 進程通信以使通知工作。

為此,我們將使用ipcRenderer和ipcMain模塊。該模塊在此處用於使用as 有效負載向主進程ipcRenderer發送事件。重構您的script.js文件以反映下面突出顯示的更改:show-notificationtask

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}`);
ipcRenderer.invoke('show-notification', newTask.value);
newTask.value = '';
});