- Electron 教程
- Electron - 主頁
- Electron - 概述
- Electron - 安裝
- Electron 是如何工作的?
- Electron - Hello World
- Electron - 構建 UI
- Electron - 檔案處理
- Electron - 原生 Node 庫
- 程序間通訊 (IPC)
- Electron - 系統對話方塊
- Electron - 選單
- Electron - 系統托盤
- Electron - 通知
- Electron - Webview
- Electron - 音訊和影片捕獲
- Electron - 定義快捷鍵
- Electron - 環境變數
- Electron - 除錯
- Electron - 打包應用程式
- Electron - 資源
- Electron 有用資源
- Electron - 快速指南
- Electron - 有用資源
- Electron - 討論
Electron - 快速指南
Electron - 概述
為什麼選擇 Electron?
Electron 透過提供具有豐富的原生(作業系統)API 的執行時,使您可以使用純 JavaScript 建立桌面應用程式。
這並不意味著 Electron 是圖形使用者介面 (GUI) 庫的 JavaScript 繫結。相反,Electron 使用網頁作為其 GUI,因此您也可以將其視為受 JavaScript 控制的最小 Chromium 瀏覽器。因此,所有 Electron 應用程式從技術上講都是在瀏覽器中執行的網頁,可以利用您的作業系統 API。
誰在使用 Electron?
Github 開發了 Electron 用於建立文字編輯器 Atom。它們都於 2014 年開源。Electron 被許多公司使用,例如 Microsoft、Github、Slack 等。
Electron 已被用於建立許多應用程式。以下是一些著名的應用程式:
- Slack 桌面版
- Wordpress 桌面應用程式
- Visual Studio Code
- Caret Markdown 編輯器
- Nylas 郵件應用程式
- GitKraken git 客戶端
Electron - 安裝
要開始使用 Electron 進行開發,您需要安裝 Node 和 npm(節點包管理器)。如果您尚未安裝這些,請訪問 Node 設定 以在您的本地系統上安裝 Node。透過在您的終端中執行以下命令來確認 Node 和 npm 是否已安裝。
node --version npm --version
以上命令將生成以下輸出:
v6.9.1 3.10.8
每當我們使用 npm 建立專案時,都需要提供一個package.json檔案,其中包含我們專案的所有詳細資訊。npm 使我們能夠輕鬆設定此檔案。讓我們設定我們的開發專案。
啟動您的終端/cmd,建立一個名為 hello-world 的新資料夾,並使用 cd 命令開啟該資料夾。
現在,要使用 npm 建立 package.json 檔案,請使用以下命令。
npm init
它會詢問您以下資訊:
只需一直按 Enter 鍵,並在“作者姓名”欄位中輸入您的姓名。
建立一個新資料夾,並使用 cd 命令開啟它。現在執行以下命令以全域性安裝 Electron。
$ npm install -g electron-prebuilt
執行完畢後,您可以透過執行以下命令檢查 Electron 是否已正確安裝:
$ electron --version
您應該獲得以下輸出:
v1.4.13
現在我們已經設定了 Electron,讓我們繼續使用它建立我們的第一個應用程式。
Electron 是如何工作的
Electron 獲取在您的package.json檔案中定義的主檔案並執行它。此主檔案建立應用程式視窗,其中包含呈現的網頁以及與作業系統的原生 GUI(圖形使用者介面)的互動。
當您使用 Electron 啟動應用程式時,會建立一個主程序。此主程序負責與作業系統的原生 GUI 互動。它建立應用程式的 GUI。
僅啟動主程序不會為應用程式使用者提供任何應用程式視窗。這些視窗由主檔案中的主程序使用BrowserWindow模組建立。然後,每個瀏覽器視窗都執行其自己的渲染器程序。渲染器程序獲取一個 HTML 檔案,該檔案引用通常的 CSS 檔案、JavaScript 檔案、影像等,並在視窗中呈現它。
主程序可以透過 Electron 中直接可用的模組訪問原生 GUI。桌面應用程式可以訪問所有 Node 模組,例如用於處理檔案的 FileSystem 模組、用於發出 HTTP 請求的請求模組等。
主程序和渲染器程序之間的區別
主程序透過建立BrowserWindow例項來建立網頁。每個BrowserWindow例項在其自己的渲染器程序中執行網頁。當BrowserWindow例項被銷燬時,相應的渲染器程序也會終止。
主程序管理所有網頁及其相應的渲染器程序。每個渲染器程序都是隔離的,只關心在其內執行的網頁。
Electron - Hello World
我們已經為我們的專案建立了一個package.json檔案。現在我們將使用 Electron 建立我們的第一個桌面應用程式。
建立一個名為main.js的新檔案。在其中輸入以下程式碼:
const {app, BrowserWindow} = require('electron')
const url = require('url')
const path = require('path')
let win
function createWindow() {
win = new BrowserWindow({width: 800, height: 600})
win.loadURL(url.format ({
pathname: path.join(__dirname, 'index.html'),
protocol: 'file:',
slashes: true
}))
}
app.on('ready', createWindow)
建立另一個檔案,這次是一個名為index.html的 HTML 檔案。在其中輸入以下程式碼。
<!DOCTYPE html>
<html>
<head>
<meta charset = "UTF-8">
<title>Hello World!</title>
</head>
<body>
<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>
使用以下命令執行此應用程式:
$ electron ./main.js
將開啟一個新視窗。它看起來如下所示:
此應用程式是如何工作的?
我們建立了一個主檔案和一個 HTML 檔案。主檔案使用兩個模組 - app 和 BrowserWindow。app 模組用於控制應用程式的事件生命週期,而 BrowserWindow 模組用於建立和控制瀏覽器視窗。
我們定義了一個createWindow函式,在其中我們建立一個新的 BrowserWindow 並將一個 URL 附加到此 BrowserWindow。這是我們在執行應用程式時呈現並顯示給我們的 HTML 檔案。
我們在 html 檔案中使用了原生 Electron 物件 process。此物件擴充套件自 Node.js process 物件,幷包含t=其所有功能,同時還添加了許多其他功能。
Electron - 構建 UI
Electron 應用程式的使用者介面使用 HTML、CSS 和 JS 構建。因此,我們也可以在這裡利用所有可用的前端 Web 開發工具。您可以使用 Angular、Backbone、React、Bootstrap 和 Foundation 等工具來構建應用程式。
您可以使用 Bower 來管理這些前端依賴項。使用以下命令安裝 bower:
$ npm install -g bower
現在您可以使用 bower 獲取所有可用的 JS 和 CSS 框架、庫、外掛等。例如,要獲取 Bootstrap 的最新穩定版本,請輸入以下命令:
$ bower install bootstrap
這將在bower_components中下載 Bootstrap。現在您可以在您的 HTML 中引用此庫。讓我們使用這些庫建立一個簡單的頁面。
現在讓我們使用 npm 命令安裝 jquery:
$ npm install --save jquery
此外,這將在我們的 view.js 檔案中需要。我們已經設定了一個 main.js,如下所示:
const {app, BrowserWindow} = require('electron')
const url = require('url')
const path = require('path')
let win
function createWindow() {
win = new BrowserWindow({width: 800, height: 600})
win.loadURL(url.format ({
pathname: path.join(__dirname, 'index.html'),
protocol: 'file:',
slashes: true
}))
}
app.on('ready', createWindow)
開啟您的index.html檔案並在其中輸入以下程式碼:
<!DOCTYPE html>
<html>
<head>
<meta charset = "UTF-8">
<title>Hello World!</title>
<link rel = "stylesheet"
href = "./bower_components/bootstrap/dist/css/bootstrap.min.css" />
</head>
<body>
<div class = "container">
<h1>This page is using Bootstrap and jQuery!</h1>
<h3 id = "click-counter"></h3>
<button class = "btn btn-success" id = "countbtn">Click here</button>
<script src = "./view.js" ></script>
</div>
</body>
</html>
建立view.js並在其中輸入點選計數器邏輯:
let $ = require('jquery') // jQuery now loaded and assigned to $
let count = 0
$('#click-counter').text(count.toString())
$('#countbtn').on('click', () => {
count ++
$('#click-counter').text(count)
})
使用以下命令執行應用程式:
$ electron ./main.js
以上命令將生成以下螢幕截圖中的輸出:
您可以像構建網站一樣構建您的原生應用程式。如果您不希望使用者受限於精確的視窗大小,您可以利用響應式設計並允許使用者以靈活的方式使用您的應用程式。
Electron - 檔案處理
檔案處理是構建桌面應用程式非常重要的一部分。幾乎所有桌面應用程式都與檔案互動。
我們將在我們的應用程式中建立一個表單,該表單將作為輸入獲取姓名和電子郵件地址。此表單將儲存到檔案中,並將建立一個列表以將其顯示為輸出。
使用main.js檔案中的以下程式碼設定您的主程序:
const {app, BrowserWindow} = require('electron')
const url = require('url')
const path = require('path')
let win
function createWindow() {
win = new BrowserWindow({width: 800, height: 600})
win.loadURL(url.format ({
pathname: path.join(__dirname, 'index.html'),
protocol: 'file:',
slashes: true
}))
}
app.on('ready', createWindow)
現在開啟index.html檔案並在其中輸入以下程式碼:
<!DOCTYPE html>
<html>
<head>
<meta charset = "UTF-8">
<title>File System</title>
<link rel = "stylesheet"
href = "./bower_components/bootstrap/dist/css/bootstrap.min.css" />
<style type = "text/css">
#contact-list {
height: 150px;
overflow-y: auto;
}
</style>
</head>
<body>
<div class = "container">
<h1>Enter Names and Email addresses of your contacts</h1>
<div class = "form-group">
<label for = "Name">Name</label>
<input type = "text" name = "Name" value = "" id = "Name"
placeholder = "Name" class = "form-control" required>
</div>
<div class = "form-group">
<label for = "Email">Email</label>
<input type = "email" name = "Email" value = "" id = "Email"
placeholder = "Email" class = "form-control" required>
</div>
<div class = "form-group">
<button class = "btn btn-primary" id = "add-to-list">Add to list!</button>
</div>
<div id = "contact-list">
<table class = "table-striped" id = "contact-table">
<tr>
<th class = "col-xs-2">S. No.</th>
<th class = "col-xs-4">Name</th>
<th class = "col-xs-6">Email</th>
</tr>
</table>
</div>
<script src = "./view.js" ></script>
</div>
</body>
</html>
現在我們需要處理新增事件。我們將在我們的view.js檔案中執行此操作。
我們將建立一個loadAndDisplayContacts()函式,該函式將最初從檔案中載入聯絡人。建立loadAndDisplayContacts()函式後,我們將為新增到列表按鈕建立一個點選處理程式。這會將條目新增到檔案和表格中。
在您的 view.js 檔案中,輸入以下程式碼:
let $ = require('jquery')
let fs = require('fs')
let filename = 'contacts'
let sno = 0
$('#add-to-list').on('click', () => {
let name = $('#Name').val()
let email = $('#Email').val()
fs.appendFile('contacts', name + ',' + email + '\n')
addEntry(name, email)
})
function addEntry(name, email) {
if(name && email) {
sno++
let updateString = '<tr><td>'+ sno + '</td><td>'+ name +'</td><td>'
+ email +'</td></tr>'
$('#contact-table').append(updateString)
}
}
function loadAndDisplayContacts() {
//Check if file exists
if(fs.existsSync(filename)) {
let data = fs.readFileSync(filename, 'utf8').split('\n')
data.forEach((contact, index) => {
let [ name, email ] = contact.split(',')
addEntry(name, email)
})
} else {
console.log("File Doesn\'t Exist. Creating new file.")
fs.writeFile(filename, '', (err) => {
if(err)
console.log(err)
})
}
}
loadAndDisplayContacts()
現在執行應用程式,使用以下命令:
$ electron ./main.js
向其中新增一些聯絡人後,應用程式將如下所示:
有關更多fs 模組 API 呼叫,請參考Node 檔案系統教程。
現在我們可以使用 Electron 處理檔案。我們將在對話方塊章節中瞭解如何在對話方塊中呼叫檔案的儲存和開啟對話方塊(原生)。
Electron - 原生 Node 庫
我們在上一章中使用了 Node 模組 fs。現在我們將瞭解一些其他可以與 Electron 一起使用的 Node 模組。
OS 模組
使用 OS 模組,我們可以獲取有關應用程式正在執行的系統的大量資訊。以下是一些在建立應用程式時有幫助的方法。這些方法幫助我們根據其執行的作業系統自定義應用程式。
| 序號 | 函式和說明 |
|---|---|
| 1 | os.userInfo([options]) os.userInfo()方法返回有關當前有效使用者的資訊。此資訊可用於個性化應用程式以供使用者使用,即使無需明確請求資訊。 |
| 2 | os.platform() os.platform()方法返回一個字串,標識作業系統平臺。這可用於根據使用者作業系統自定義應用程式。 |
| 3 | os.homedir() os.homedir()方法將當前使用者的 home 目錄作為字串返回。通常,所有使用者的配置都位於使用者的 home 目錄中。因此,這可以用於我們應用程式的相同目的。 |
| 4 | os.arch() os.arch()方法返回一個字串,標識作業系統 CPU 架構。這可以在異構架構上執行時使用,以使您的應用程式適應該系統。 |
| 5 | os.EOL 一個字串常量,定義作業系統特定的行尾標記。在主機作業系統上的檔案中結束行時應使用此標記。 |
使用相同的主檔案和以下 HTML 檔案,我們可以在螢幕上列印這些屬性:
<html>
<head>
<title>OS Module</title>
</head>
<body>
<script>
let os = require('os')
document.write('User Info: ' + JSON.stringify(os.userInfo()) + '<br>' +
'Platform: ' + os.platform() + '<br>' +
'User home directory: ' + os.homedir() + '<br>' +
'OS Architecture: ' + os.arch() + '<br>')
</script>
</body>
</html>
現在執行應用程式,使用以下命令:
$ electron ./main.js
以上命令將生成以下輸出:
User Info: {"uid":1000,"gid":1000,"username":"ayushgp","homedir":"/home/ayushgp",
"shell":"/usr/bin/zsh"}
Platform: linux
User home directory: /home/ayushgp
OS Architecture: x64
Net 模組
net 模組用於應用程式中的網路相關工作。我們可以使用此模組建立伺服器和套接字連線。通常,建議使用 npm 的包裝器模組而不是 net 模組來執行網路相關任務。
下表列出了該模組中最有用的方法:
| 序號 | 函式和說明 |
|---|---|
| 1 | net.createServer([options][, connectionListener]) 建立一個新的 TCP 伺服器。connectionListener 引數會自動設定為 'connection' 事件的監聽器。 |
| 2 | net.createConnection(options[, connectionListener]) 一個工廠方法,它返回一個新的 'net.Socket' 並連線到提供的地址和埠。 |
| 3 | net.Server.listen(port[, host][, backlog][, callback]) 開始在指定的埠和主機上接受連線。如果省略主機,則伺服器將接受定向到任何 IPv4 地址的連線。 |
| 4 | net.Server.close([callback]) 當所有連線都結束且伺服器發出 'close' 事件時,最終關閉。 |
| 5 | net.Socket.connect(port[, host][, connectListener]) 為給定的套接字開啟連線。如果提供了埠和主機,則套接字將作為 TCP 套接字開啟。 |
net 模組還帶有一些其他方法。要獲取更全面的列表,請參閱 此處。
現在,讓我們建立一個使用 net 模組建立到伺服器的連線的 Electron 應用程式。我們需要建立一個新檔案,server.js:
var net = require('net');
var server = net.createServer(function(connection) {
console.log('Client Connected');
connection.on('end', function() {
console.log('client disconnected');
});
connection.write('Hello World!\r\n');
connection.pipe(connection);
});
server.listen(8080, function() {
console.log('Server running on https://:8080');
});
使用相同的 main.js 檔案,將 HTML 檔案替換為以下內容:
<html>
<head>
<title>net Module</title>
</head>
<body>
<script>
var net = require('net');
var client = net.connect({port: 8080}, function() {
console.log('Connection established!');
});
client.on('data', function(data) {
document.write(data.toString());
client.end();
});
client.on('end', function() {
console.log('Disconnected :(');
});
</script>
</body>
</html>
使用以下命令執行伺服器:
$ node server.js
使用以下命令執行應用程式:
$ electron ./main.js
以上命令將生成以下輸出:
觀察到我們自動連線到伺服器並自動斷開連線。
我們還有一些其他節點模組,可以使用 Electron 直接在前端使用。這些模組的使用取決於您在其中使用它們的場景。
Electron - 程序間通訊
Electron 為我們提供了 2 個 IPC(程序間通訊)模組,稱為 ipcMain 和 ipcRenderer。
ipcMain 模組用於從主程序非同步通訊到渲染器程序。在主程序中使用時,該模組處理從渲染器程序(網頁)傳送的非同步和同步訊息。從渲染器傳送的訊息將被髮送到此模組。
ipcRenderer 模組用於從渲染器程序非同步通訊到主程序。它提供了一些方法,以便您可以從渲染器程序(網頁)向主程序傳送同步和非同步訊息。您還可以接收來自主程序的回覆。
我們將建立一個主程序和一個渲染器程序,它們將使用上述模組相互發送訊息。
建立一個名為 main_process.js 的新檔案,內容如下:
const {app, BrowserWindow} = require('electron')
const url = require('url')
const path = require('path')
const {ipcMain} = require('electron')
let win
function createWindow() {
win = new BrowserWindow({width: 800, height: 600})
win.loadURL(url.format ({
pathname: path.join(__dirname, 'index.html'),
protocol: 'file:',
slashes: true
}))
}
// Event handler for asynchronous incoming messages
ipcMain.on('asynchronous-message', (event, arg) => {
console.log(arg)
// Event emitter for sending asynchronous messages
event.sender.send('asynchronous-reply', 'async pong')
})
// Event handler for synchronous incoming messages
ipcMain.on('synchronous-message', (event, arg) => {
console.log(arg)
// Synchronous event emmision
event.returnValue = 'sync pong'
})
app.on('ready', createWindow)
現在建立一個新的 index.html 檔案並在其中新增以下程式碼。
<!DOCTYPE html>
<html>
<head>
<meta charset = "UTF-8">
<title>Hello World!</title>
</head>
<body>
<script>
const {ipcRenderer} = require('electron')
// Synchronous message emmiter and handler
console.log(ipcRenderer.sendSync('synchronous-message', 'sync ping'))
// Async message handler
ipcRenderer.on('asynchronous-reply', (event, arg) => {
console.log(arg)
})
// Async message sender
ipcRenderer.send('asynchronous-message', 'async ping')
</script>
</body>
</html>
使用以下命令執行應用程式:
$ electron ./main_process.js
以上命令將生成以下輸出:
// On your app console Sync Pong Async Pong // On your terminal where you ran the app Sync Ping Async Ping
建議不要在渲染器程序上執行繁重/阻塞任務的計算。始終使用 IPC 將這些任務委託給主程序。這有助於保持應用程式的執行速度。
Electron - 系統對話方塊
對於任何應用程式來說,使用者友好性都非常重要。因此,您不應使用 alert() 呼叫建立對話方塊。Electron 提供了一個非常好的介面來完成建立對話方塊的任務。讓我們來看一下。
Electron 提供了一個 dialog 模組,我們可以使用它來顯示用於開啟和儲存檔案、警報等的本機系統對話方塊。
讓我們直接跳到一個示例,並建立一個應用程式來顯示簡單的文字檔案。
建立一個新的 main.js 檔案並在其中輸入以下程式碼:
const {app, BrowserWindow} = require('electron')
const url = require('url')
const path = require('path')
const {ipcMain} = require('electron')
let win
function createWindow() {
win = new BrowserWindow({width: 800, height: 600})
win.loadURL(url.format ({
pathname: path.join(__dirname, 'index.html'),
protocol: 'file:',
slashes: true
}))
}
ipcMain.on('openFile', (event, path) => {
const {dialog} = require('electron')
const fs = require('fs')
dialog.showOpenDialog(function (fileNames) {
// fileNames is an array that contains all the selected
if(fileNames === undefined) {
console.log("No file selected");
} else {
readFile(fileNames[0]);
}
});
function readFile(filepath) {
fs.readFile(filepath, 'utf-8', (err, data) => {
if(err){
alert("An error ocurred reading the file :" + err.message)
return
}
// handle the file content
event.sender.send('fileData', data)
})
}
})
app.on('ready', createWindow)
此程式碼將在我們的主程序從渲染器程序接收 'openFile' 訊息時彈出開啟對話方塊。此訊息將檔案內容重定向回渲染器程序。現在,我們將必須列印內容。
現在,建立一個新的 index.html 檔案,內容如下:
<!DOCTYPE html>
<html>
<head>
<meta charset = "UTF-8">
<title>File read using system dialogs</title>
</head>
<body>
<script type = "text/javascript">
const {ipcRenderer} = require('electron')
ipcRenderer.send('openFile', () => {
console.log("Event sent.");
})
ipcRenderer.on('fileData', (event, data) => {
document.write(data)
})
</script>
</body>
</html>
現在,每當我們執行應用程式時,都會彈出一個本機開啟對話方塊,如下面的螢幕截圖所示:
選擇要顯示的檔案後,其內容將顯示在應用程式視窗中:
這只是 Electron 提供的四個對話方塊之一。儘管它們都具有類似的用法。一旦您學會了如何使用 showOpenDialog,那麼您就可以使用任何其他對話方塊。
具有相同功能的對話方塊有:
- showSaveDialog([browserWindow, ]options[, callback])
- showMessageDialog([browserWindow, ]options[, callback])
- showErrorDialog(title, content)
Electron - 選單
桌面應用程式帶有兩種型別的選單——應用程式選單(在頂部欄上)和上下文選單(右鍵單擊選單)。我們將在本章中學習如何建立這兩者。
我們將使用兩個模組——Menu 和 MenuItem 模組。請注意,Menu 和 MenuItem 模組僅在主程序中可用。要在渲染器程序中使用這些模組,您需要 remote 模組。當我們建立上下文選單時,我們將遇到它。
現在,讓我們為主程序建立一個新的 main.js 檔案:
const {app, BrowserWindow, Menu, MenuItem} = require('electron')
const url = require('url')
const path = require('path')
let win
function createWindow() {
win = new BrowserWindow({width: 800, height: 600})
win.loadURL(url.format ({
pathname: path.join(__dirname, 'index.html'),
protocol: 'file:',
slashes: true
}))
}
const template = [
{
label: 'Edit',
submenu: [
{
role: 'undo'
},
{
role: 'redo'
},
{
type: 'separator'
},
{
role: 'cut'
},
{
role: 'copy'
},
{
role: 'paste'
}
]
},
{
label: 'View',
submenu: [
{
role: 'reload'
},
{
role: 'toggledevtools'
},
{
type: 'separator'
},
{
role: 'resetzoom'
},
{
role: 'zoomin'
},
{
role: 'zoomout'
},
{
type: 'separator'
},
{
role: 'togglefullscreen'
}
]
},
{
role: 'window',
submenu: [
{
role: 'minimize'
},
{
role: 'close'
}
]
},
{
role: 'help',
submenu: [
{
label: 'Learn More'
}
]
}
]
const menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu)
app.on('ready', createWindow)
我們在這裡從模板構建選單。這意味著我們將選單作為 JSON 提供給函式,它將處理其餘部分。現在,我們必須將此選單設定為應用程式選單。
現在建立一個名為 index.html 的空 HTML 檔案,並使用以下命令執行此應用程式:
$ electron ./main.js
在應用程式選單的正常位置,您將看到一個基於上述模板的選單。
我們從主程序建立了此選單。現在讓我們為我們的應用程式建立一個上下文選單。我們將在我們的 HTML 檔案中執行此操作:
<!DOCTYPE html>
<html>
<head>
<meta charset = "UTF-8">
<title>Menus</title>
</head>
<body>
<script type = "text/javascript">
const {remote} = require('electron')
const {Menu, MenuItem} = remote
const menu = new Menu()
// Build menu one item at a time, unlike
menu.append(new MenuItem ({
label: 'MenuItem1',
click() {
console.log('item 1 clicked')
}
}))
menu.append(new MenuItem({type: 'separator'}))
menu.append(new MenuItem({label: 'MenuItem2', type: 'checkbox', checked: true}))
menu.append(new MenuItem ({
label: 'MenuItem3',
click() {
console.log('item 3 clicked')
}
}))
// Prevent default action of right click in chromium. Replace with our menu.
window.addEventListener('contextmenu', (e) => {
e.preventDefault()
menu.popup(remote.getCurrentWindow())
}, false)
</script>
</body>
</html>
我們使用 remote 模組匯入了 Menu 和 MenuItem 模組;然後,我們建立了一個選單並將我們的選單項逐一附加到其中。此外,我們阻止了 chromium 中右鍵單擊的預設操作,並將其替換為我們的選單。
在 Electron 中建立選單是一項非常簡單的任務。現在,您可以將您的事件處理程式附加到這些專案並根據您的需要處理事件。
Electron - 系統托盤
系統托盤是應用程式視窗外部的選單。在 MacOS 和 Ubuntu 上,它位於螢幕的右上角。在 Windows 上,它位於右下角。我們可以使用 Electron 在系統托盤中為我們的應用程式建立選單。
建立一個新的 main.js 檔案並將以下程式碼新增到其中。準備好一個 png 檔案以用於系統托盤圖示。
const {app, BrowserWindow} = require('electron')
const url = require('url')
const path = require('path')
let win
function createWindow() {
win = new BrowserWindow({width: 800, height: 600})
win.loadURL(url.format ({
pathname: path.join(__dirname, 'index.html'),
protocol: 'file:',
slashes: true
}))
}
app.on('ready', createWindow)
在設定了基本瀏覽器視窗後,我們將建立一個新的 index.html 檔案,內容如下:
<!DOCTYPE html>
<html>
<head>
<meta charset = "UTF-8">
<title>Menus</title>
</head>
<body>
<script type = "text/javascript">
const {remote} = require('electron')
const {Tray, Menu} = remote
const path = require('path')
let trayIcon = new Tray(path.join('','/home/ayushgp/Desktop/images.png'))
const trayMenuTemplate = [
{
label: 'Empty Application',
enabled: false
},
{
label: 'Settings',
click: function () {
console.log("Clicked on settings")
}
},
{
label: 'Help',
click: function () {
console.log("Clicked on Help")
}
}
]
let trayMenu = Menu.buildFromTemplate(trayMenuTemplate)
trayIcon.setContextMenu(trayMenu)
</script>
</body>
</html>
我們使用 Tray 子模組建立了托盤。然後,我們使用模板建立了一個選單,並將選單進一步附加到我們的托盤物件。
使用以下命令執行應用程式:
$ electron ./main.js
當您執行上述命令時,請檢查您的系統托盤以檢視您使用的圖示。我為我的應用程式使用了笑臉。上述命令將生成以下輸出:
Electron - 通知
Electron 僅為 MacOS 提供本機通知 API。因此,我們不會使用它,而是將使用名為 node-notifier 的 npm 模組。它允許我們向 Windows、MacOS 和 Linux 上的使用者傳送通知。
使用以下命令在您的應用程式資料夾中安裝 node-notifier 模組:
$ npm install --save node-notifier
現在讓我們建立一個應用程式,該應用程式有一個按鈕,每次我們單擊此按鈕時都會生成一個通知。
建立一個新的 main.js 檔案並在其中輸入以下程式碼:
const {app, BrowserWindow} = require('electron')
const url = require('url')
const path = require('path')
let win
function createWindow() {
win = new BrowserWindow({width: 800, height: 600})
win.loadURL(url.format ({
pathname: path.join(__dirname, 'index.html'),
protocol: 'file:',
slashes: true
}))
}
app.on('ready', createWindow)
現在讓我們建立網頁和指令碼,這些網頁和指令碼將觸發通知。建立一個新的 index.html 檔案,內容如下:
<!DOCTYPE html>
<html>
<head>
<meta charset = "UTF-8">
<title>Menus</title>
</head>
<body>
<button type = "button" id = "notify" name = "button">
Click here to trigger a notification!</button>
<script type = "text/javascript">
const notifier = require('node-notifier')
const path = require('path');
document.getElementById('notify').onclick = (event) => {
notifier.notify ({
title: 'My awesome title',
message: 'Hello from electron, Mr. User!',
icon: path.join('','/home/ayushgp/Desktop/images.png'), // Absolute path
(doesn't work on balloons)
sound: true, // Only Notification Center or Windows Toasters
wait: true // Wait with callback, until user action is taken
against notification
}, function (err, response) {
// Response is response from notification
});
notifier.on('click', function (notifierObject, options) {
console.log("You clicked on the notification")
});
notifier.on('timeout', function (notifierObject, options) {
console.log("Notification timed out!")
});
}
</script>
</body>
</html>
notify 方法允許我們向其傳遞一個包含標題、訊息、縮圖等資訊的物件,這些資訊有助於我們自定義通知。我們還可以為通知設定一些事件監聽器。
現在,使用以下命令執行應用程式:
$ electron ./main.js
當您單擊我們建立的按鈕時,您將看到來自作業系統的本機通知,如下面的螢幕截圖所示:
我們還處理了使用者單擊通知或通知超時時的事件。這些方法有助於使應用程式更具互動性,如果它在後臺執行。
Electron - Webview
webview 標籤用於在您的 Electron 應用程式中嵌入“訪客”內容,例如網頁。此內容包含在 webview 容器中。應用程式中嵌入的頁面控制此內容的顯示方式。
webview 在與您的應用程式不同的程序中執行。為了確保來自惡意內容的安全,webview 沒有與您的網頁相同的許可權。這可以保護您的應用程式免受嵌入內容的侵害。您的應用程式和嵌入頁面之間的所有互動都將是非同步的。
讓我們考慮一個示例來了解如何在我們的 Electron 應用程式中嵌入外部網頁。我們將在應用程式的右側嵌入 tutorialspoint 網站。建立一個新的 main.js 檔案,內容如下:
const {app, BrowserWindow} = require('electron')
const url = require('url')
const path = require('path')
let win
function createWindow() {
win = new BrowserWindow({width: 800, height: 600})
win.loadURL(url.format ({
pathname: path.join(__dirname, 'index.html'),
protocol: 'file:',
slashes: true
}))
}
app.on('ready', createWindow)
現在我們已經設定了主程序,讓我們建立將嵌入 tutorialspoint 網站的 HTML 檔案。建立一個名為 index.html 的檔案,內容如下:
<!DOCTYPE html>
<html>
<head>
<meta charset = "UTF-8">
<title>Menus</title>
</head>
<body>
<div>
<div>
<h2>We have the website embedded below!</h2>
</div>
<webview id = "foo" src = "https://tutorialspoint.tw/" style =
"width:400px; height:480px;">
<div class = "indicator"></div>
</webview>
</div>
<script type = "text/javascript">
// Event handlers for loading events.
// Use these to handle loading screens, transitions, etc
onload = () => {
const webview = document.getElementById('foo')
const indicator = document.querySelector('.indicator')
const loadstart = () => {
indicator.innerText = 'loading...'
}
const loadstop = () => {
indicator.innerText = ''
}
webview.addEventListener('did-start-loading', loadstart)
webview.addEventListener('did-stop-loading', loadstop)
}
</script>
</body>
</html>
使用以下命令執行應用程式:
$ electron ./main.js
以上命令將生成以下輸出:
webview 標籤也可以用於其他資源。webview 元素具有一系列它發出的事件,這些事件在官方文件中列出。您可以使用這些事件來改進功能,具體取決於 webview 中發生的事情。
每當您從 Internet 嵌入指令碼或其他資源時,建議使用 webview。建議這樣做,因為它具有極大的安全優勢,並且不會妨礙正常行為。
Electron - 音訊和影片捕獲
如果您正在構建用於螢幕共享、語音備忘錄等的應用程式,則音訊和影片捕獲是重要的特性。如果您需要應用程式捕獲個人資料圖片,它們也很有用。
我們將使用 getUserMedia HTML5 API 來使用 Electron 捕獲音訊和影片流。首先讓我們在 main.js 檔案中設定我們的主程序,如下所示:
const {app, BrowserWindow} = require('electron')
const url = require('url')
const path = require('path')
let win
// Set the path where recordings will be saved
app.setPath("userData", __dirname + "/saved_recordings")
function createWindow() {
win = new BrowserWindow({width: 800, height: 600})
win.loadURL(url.format({
pathname: path.join(__dirname, 'index.html'),
protocol: 'file:',
slashes: true
}))
}
app.on('ready', createWindow)
現在我們已經設定了主程序,讓我們建立將捕獲此內容的 HTML 檔案。建立一個名為 index.html 的檔案,內容如下:
<!DOCTYPE html>
<html>
<head>
<meta charset = "UTF-8">
<title>Audio and Video</title>
</head>
<body>
<video autoplay></video>
<script type = "text/javascript">
function errorCallback(e) {
console.log('Error', e)
}
navigator.getUserMedia({video: true, audio: true}, (localMediaStream) => {
var video = document.querySelector('video')
video.src = window.URL.createObjectURL(localMediaStream)
video.onloadedmetadata = (e) => {
// Ready to go. Do some stuff.
};
}, errorCallback)
</script>
</body>
</html>
上述程式將生成以下輸出:
您現在擁有來自網路攝像頭和麥克風的流。您可以透過網路傳送此流或以您喜歡的格式儲存此流。
請檢視MDN 文件,瞭解如何捕獲影像以獲取來自網路攝像頭的影像並將其儲存。這是使用 HTML5 的getUserMedia API 完成的。您還可以使用 Electron 附帶的desktopCapturer模組捕獲使用者桌面。現在讓我們看一個獲取螢幕流的示例。
使用上面相同的 main.js 檔案,並編輯 index.html 檔案使其包含以下內容:
desktopCapturer.getSources({types: ['window', 'screen']}, (error, sources) => {
if (error) throw error
for (let i = 0; i < sources.length; ++i) {
if (sources[i].name === 'Your Window Name here!') {
navigator.webkitGetUserMedia({
audio: false,
video: {
mandatory: {
chromeMediaSource: 'desktop',
chromeMediaSourceId: sources[i].id,
minWidth: 1280,
maxWidth: 1280,
minHeight: 720,
maxHeight: 720
}
}
}, handleStream, handleError)
return
}
}
})
function handleStream (stream) {
document.querySelector('video').src = URL.createObjectURL(stream)
}
function handleError (e) {
console.log(e)
}
我們使用了desktopCapturer模組來獲取每個開啟視窗的資訊。現在,您可以根據傳遞給上述if 語句的名稱捕獲特定應用程式或整個螢幕的事件。這隻會將該螢幕上發生的內容流式傳輸到您的應用程式。
您可以參考此 StackOverflow 問題以詳細瞭解其用法。
Electron - 定義快捷鍵
我們通常會記住我們在 PC 上每天使用的所有應用程式的某些快捷方式。為了使您的應用程式對使用者感覺直觀且易於訪問,您必須允許使用者使用快捷方式。
我們將使用 globalShortcut 模組在我們的應用程式中定義快捷方式。請注意,加速鍵是字串,可以包含多個修飾符和鍵程式碼,並由 + 字元組合。這些加速鍵用於在整個應用程式中定義鍵盤快捷方式。
讓我們考慮一個示例並建立一個快捷方式。為此,我們將遵循對話方塊示例,其中我們使用開啟對話方塊開啟檔案。我們將註冊一個CommandOrControl+O快捷方式以調出對話方塊。
我們的main.js程式碼將與之前相同。因此,建立一個新的main.js檔案,並在其中輸入以下程式碼:
const {app, BrowserWindow} = require('electron')
const url = require('url')
const path = require('path')
const {ipcMain} = require('electron')
let win
function createWindow() {
win = new BrowserWindow({width: 800, height: 600})
win.loadURL(url.format ({
pathname: path.join(__dirname, 'index.html'),
protocol: 'file:',
slashes: true
}))
}
ipcMain.on('openFile', (event, path) => {
const {dialog} = require('electron')
const fs = require('fs')
dialog.showOpenDialog(function (fileNames) {
// fileNames is an array that contains all the selected
if(fileNames === undefined)
console.log("No file selected")
else
readFile(fileNames[0])
})
function readFile(filepath){
fs.readFile(filepath, 'utf-8', (err, data) => {
if(err){
alert("An error ocurred reading the file :" + err.message)
return
}
// handle the file content
event.sender.send('fileData', data)
})
}
})
app.on('ready', createWindow)
每當我們的主程序從渲染器程序接收“openFile”訊息時,此程式碼都會彈出開啟對話方塊。之前,此對話方塊在應用程式執行時彈出。現在讓我們將其限制為僅在我們按下CommandOrControl+O時開啟。
現在建立一個新的index.html檔案,內容如下:
<!DOCTYPE html>
<html>
<head>
<meta charset = "UTF-8">
<title>File read using system dialogs</title>
</head>
<body>
<p>Press CTRL/CMD + O to open a file. </p>
<script type = "text/javascript">
const {ipcRenderer, remote} = require('electron')
const {globalShortcut} = remote
globalShortcut.register('CommandOrControl+O', () => {
ipcRenderer.send('openFile', () => {
console.log("Event sent.");
})
ipcRenderer.on('fileData', (event, data) => {
document.write(data)
})
})
</script>
</body>
</html>
我們註冊了一個新的快捷方式,並傳遞了一個回撥函式,該函式將在我們按下此快捷方式時執行。我們可以根據需要登出快捷方式。
現在,一旦應用程式開啟,我們將收到使用我們剛剛定義的快捷方式開啟檔案的訊息。
可以透過允許使用者為定義的操作選擇自己的快捷方式來使這些快捷方式可自定義。
Electron - 環境變數
環境變數控制應用程式配置和行為,而無需更改程式碼。某些 Electron 行為由環境變數控制,因為它們在命令列標誌和應用程式程式碼之前初始化。
Electron 中編碼了兩種環境變數——生產變數和開發變數。
生產變數
以下環境變數旨在在打包的 Electron 應用程式的執行時使用。
| 序號 | 變數和描述 |
|---|---|
| 1 | GOOGLE_API_KEY Electron 包含一個硬編碼的 API 金鑰,用於向 Google 的地理編碼 Web 服務發出請求。由於此 API 金鑰包含在每個版本的 Electron 中,因此它通常會超出其使用配額。 要解決此問題,您可以在環境中提供自己的 Google API 金鑰。在開啟任何將進行地理編碼請求的瀏覽器視窗之前,將以下程式碼放在您的主程序檔案中: process.env.GOOGLE_API_KEY = 'YOUR_KEY_HERE' |
| 2 | ELECTRON_RUN_AS_NODE 將程序作為正常的 Node.js 程序啟動。 |
| 3 | ELECTRON_FORCE_WINDOW_MENU_BAR(僅限 Linux) 不要在 Linux 上使用全域性選單欄。 |
開發變數
以下環境變數主要用於開發和除錯目的。
| 序號 | 變數和描述 |
|---|---|
| 1 | ELECTRON_ENABLE_LOGGING 將 Chrome 的內部日誌列印到控制檯。 |
| 2 | ELECTRON_ENABLE_STACK_DUMPING 當 Electron 崩潰時,將堆疊跟蹤列印到控制檯。 |
| 3 | ELECTRON_DEFAULT_ERROR_MODE 當 Electron 崩潰時顯示 Windows 的崩潰對話方塊。 |
要將任何這些環境變數設定為 true,請在您的控制檯中設定它。例如,如果要啟用日誌記錄,請使用以下命令:
對於 Windows
> set ELECTRON_ENABLE_LOGGING=true
對於 Linux
$ export ELECTRON_ENABLE_LOGGING=true
請注意,您需要在每次重新啟動計算機時都設定這些環境變數。如果要避免這樣做,請將這些行新增到您的.bashrc檔案中。
Electron - 除錯
我們有兩個程序執行我們的應用程式——主程序和渲染器程序。
由於渲染器程序是在我們的瀏覽器視窗中執行的,因此我們可以使用 Chrome Devtools 除錯它。要開啟 DevTools,請使用快捷鍵“Ctrl+Shift+I”或<F12>鍵。您可以檢視此處如何使用 devtools。
當您開啟 DevTools 時,您的應用程式將如下面的螢幕截圖所示:
除錯主程序
Electron 瀏覽器視窗中的 DevTools 只能除錯在該視窗中執行的 JavaScript(即網頁)。要除錯在主程序中執行的 JavaScript,您需要使用外部偵錯程式並使用--debug或--debug-brk開關啟動 Electron。
Electron 將在指定的埠上偵聽 V8 偵錯程式協議訊息;外部偵錯程式需要在此埠上連線。預設埠為 5858。
使用以下命令執行您的應用程式:
$ electron --debug = 5858 ./main.js
現在您將需要一個支援 V8 偵錯程式協議的偵錯程式。您可以為此目的使用 VSCode 或 node-inspector。例如,讓我們按照以下步驟設定 VSCode。請按照以下步驟進行設定:
下載並安裝VSCode。在 VSCode 中開啟您的 Electron 專案。
新增一個檔案.vscode/launch.json,其中包含以下配置:
{
"version": "1.0.0",
"configurations": [
{
"name": "Debug Main Process",
"type": "node",
"request": "launch",
"cwd": "${workspaceRoot}",
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron",
"program": "${workspaceRoot}/main.js"
}
]
}
注意 - 對於 Windows,請使用"${workspaceRoot}/node_modules/.bin/electron.cmd"作為runtimeExecutable。
在main.js中設定一些斷點,並在除錯檢視中開始除錯。當您遇到斷點時,螢幕將如下所示:
VSCode 偵錯程式非常強大,將幫助您快速糾正錯誤。您還有其他選擇,例如node-inspector,用於除錯 Electron 應用程式。
Electron - 打包應用程式
打包和分發應用程式是桌面應用程式開發過程中的一個組成部分。由於 Electron 是一個跨平臺的桌面應用程式開發框架,因此所有平臺的應用程式打包和分發也應該是一種無縫的體驗。
Electron 社群建立了一個專案,electron-packager,它為我們處理了相同的問題。它允許我們透過 JS 或 CLI 使用特定於作業系統的捆綁包(.app、.exe 等)打包和分發我們的 Electron 應用程式。
支援的平臺
Electron Packager 在以下主機平臺上執行:
- Windows(32/64 位)
- OS X
- Linux(x86/x86_64)
它為以下目標平臺生成可執行檔案/捆綁包:
- Windows(也稱為 win32,適用於 32/64 位)
- OS X(也稱為 darwin)/ Mac App Store(也稱為 mas)
- Linux(適用於 x86、x86_64 和 armv7l 架構)
安裝
使用以下命令安裝 electron packager:
# for use in npm scripts $ npm install electron-packager --save-dev # for use from cli $ npm install electron-packager -g
打包應用程式
在本節中,我們將瞭解如何從命令列執行打包程式。命令的基本形式為:
electron-packager <sourcedir> <appname> --platform=<platform> --arch=<arch> [optional flags...]
這將:
查詢或下載 Electron 的正確版本。
使用該版本的 Electron 在<output-folder>/<appname>-<platform>-<arch>中建立一個應用程式。
在兩種情況下可以省略--platform和--arch。如果您改為指定--all,則將為所有有效的目標平臺/體系結構組合建立捆綁包。否則,將為主機平臺/體系結構建立一個單個捆綁包。
Electron - 資源
我們使用了以下資源來了解更多關於 Electron 的資訊。我們在建立本教程時參考了這些資源。
最重要的資源是Electron 文件。該文件全面涵蓋了框架的幾乎所有功能和特性。它們足以幫助您構建應用程式。
在electron-sample-apps儲存庫中也提供了一些非常好的 Electron 示例。
影片資源
使用 JavaScript 和 Electron 進行快速跨平臺桌面應用程式開發
博文
使用 HTML、JS 和 Electron 建立您的第一個桌面應用程式