我的electron教程系列
electron教程(一): electron的安裝和項目的創建
electron教程(番外篇一): 開發環境及插件, VSCode調試, ESLint + Google JavaScript Style Guide代碼規范
electron教程(番外篇二): 使用TypeScript版本的electron, VSCode調試TypeScript, TS版本的ESLint
electron教程(二): http服務器, ws服務器, 子進程管理
electron教程(三): 使用ffi-napi引入C++的dll
electron教程(四): 使用electron-builder或electron-packager將項目打包為可執行桌面程序(.exe)
引言
這次, 我們一起通過幾個例子, 進一步了解node.js+electron.
三個例子:
1. 搭建一個http服務器, 通過web對服務器進行訪問
2. 搭建一個ws服務器, 通過web向服務器發送消息
3. 進程管理, 打開/關閉一個外部進程
例子1: 一個http服務器
1. 部署node.js+electron環境
按步驟完成electron教程(一): electron的安裝和項目的創建所介紹的內容.
2. 安裝http-server
確保你的cmd工作目錄為項目根目錄.
執行指令:
yarn add http-server --save
3. 在main.js中添加http服務器
在main.js的最下方, 添加如下代碼:
// http-server
const httpServer = require('http-server');
httpServer.createServer().listen(8080);
在這段代碼中:
我們創建了一個httpServer
對象
const httpServer = require('http-server');
這個對象是通過http-server
模塊創建出來的.
使用httpServer對象, 創建一個http服務器
, 並且監聽了8080端口
.
服務器啟動后, 用戶就可以通過瀏覽器來訪問我們的服務器了.
4. 啟動程序!
執行指令:
npm start
在自己的瀏覽器中,訪問http://localhost:8080/index.html
,就會得到本地的index.html文件
(這是chrome瀏覽器打開的效果)
例子2: 一個ws服務器
1. 部署node.js+electron環境
node.js+electron教程(一): 安裝nodejs和electron
2. 安裝ws
確保你的cmd工作目錄為項目根目錄.
執行指令:
yarn add ws --save
3. 在main.js中添加ws服務器
在main.js的最下方, 添加如下代碼:
// ws-服務器
const WebSocketServer = require('ws').Server;
wss = new WebSocketServer({port: 12122});
wss.on('connection', (ws) => {
// 有客戶端連接時, 打印一條日志
console.log('client connected');
// 並且創建'message'監聽
ws.on('message', (message) => {
// 直接將消息打印出來
console.log(message);
});
});
在這段代碼中:
我們創建了一個WebSocketServer
對象
const WebSocketServer = require('ws').Server;
這個對象是通過ws
模塊創建出來的.
使用WebSocketServer
對象, 創建一個ws服務器
叫做wss
對象, 並且監聽了12122端口
.
為wss對象的兩個事件分別綁定了回調:
connection
事件, 有客戶端連接時, 打印一條日志.
message
事件, 直接將消息打印出來.
4. 在index.html中引入jquery
在jquery官網下載jquery庫, 將jquery.min.js
放在html目錄
下的lib目錄
中.
並在index.html的<head>
和</head>
塊中, 添加如下代碼:
<script type="text/javascript" src="./lib/jquery.min.js"></script>
5. 在index.html中, 添加一個輸入框和按鈕
在index.html的<body>
和</body>
塊中的最下方, 添加如下代碼:
<div class="vertical-center">
<div class="container">
<p> </p>
<form role="form" id="chat_form" onsubmit="sendWsMessage(); return false;">
<div class="form-group">
<input class="form-control" type="text" name="message" id="message"
placeholder="Type text to echo in here" value="" />
</div>
<button type="button" id="send" class="btn btn-primary"
onclick="sendWsMessage();">
Send!
</button>
</form>
</div>
</div>
在這段代碼中:
我們首先定義了一個輸入框即表單form
, 該表單包含了input
元素, 用戶可以在該輸入框內填寫字符, 而html可以通過message
來獲取輸入框內的字符.
接着我們定義了一個按鈕button
, 在網頁中按鈕顯示為send!
, 並給該按鈕的左鍵點擊事件onclick
綁定了一個函數onclick="sendWsMessage();"
, 當用戶左鍵點擊這個send!
按鈕, 就會觸發sendWsMessage()
函數.
6. 在index.html中, 定義ws客戶端
在index.html的<script>
和</script>
塊中的最下方, 添加如下代碼:
const ws = new WebSocket("ws://localhost:12122");
這段代碼中:
我們先實例化了一個websocket
對象ws
, 其參數為要連接的地址, 這里使用本機localhost的12122端口
, 如果你是在局域網內啟動, 也可以將localhost
替換為你的內網ip.
7. 在index.html中, 定義按鈕的sendWsMessage()函數
在index.html的<script>
和</script>
塊中的最下方, 添加如下代碼:
function sendWsMessage() {
ws.send($('#message').val());
}
這段代碼中:
我們調用了websocket對象ws
的send()
方法, 向目標地址localhost的12122端口
發送數據, 數據的內容是通過#message
獲取的, 即用戶在輸入框
內輸入的數據.
前端流程:
當用戶點擊
send!
按鈕, 獲取輸入框
內的內容, 通過ws
, 向localhost的12122端口
發送.
8. 啟動
執行指令:
npm start
此時的程序界面, 出現了輸入框
和send!
按鈕.
回到cmd中, 發現cmd打印了一條日志
client connected
那是因為我們在ws服務器(main.js)中, 添加了如下代碼:
wss.on('connection', (ws) => {
// 有客戶端連接時, 打印一條日志
console.log('client connected');
當程序啟動的時候, 自動建立了連接, 所以打印了這條日志.
如果你已經完成了例子1, 並且還沒有刪除代碼的話, 試着再次從瀏覽器中訪問http://localhost:8080/index.html
, 是否又打印出了一條相同的日志?
現在, 我們試試發送消息的功能:
在程序界面的輸入框內, 輸入一個
Hello electron!
, 點擊send!
回到cmd中, 成功打印了日志Hello electron!
.
前端流程:
當用戶點擊
send!
按鈕, 獲取輸入框
內的內容, 通過ws
, 向localhost的12122端口
發送.
后端流程:
當ws服務器收到消息的時候, 直接將消息打印出來.
例子3: 進程管理
1. 部署node.js+electron環境
node.js+electron教程(一): 安裝nodejs和electron
2. 在main.js中, 啟動一個外部進程
在main.js中, 添加如下代碼:
const myChildProccess = require('child_process');
// 打開一個子進程notepad++
const mySpawn = myChildProccess.spawn(
'e:\\Application\\Notepad++\\notepad++.exe');
在這段代碼中:
我們創建了一個myChildProccess
對象
const myChildProccess = require('child_process');
這個對象是通過child_process
模塊創建出來的, 該模塊主要用於創建子進程.
我們調用這個對象的spwan()
方法, 啟動一個子進程. 該方法接受一個字符串參數, 是子進程的路徑, 注意路徑的書寫方式.
3. 測試
執行命令:
npm start
在程序啟動后, notepad++也緊跟着啟動了, notepad++就是本程序啟動的子進程.
electron可以啟動子進程, 自然也可以關閉子進程, 不然算什么進程管理?
現在我們關閉程序, 繼續進行下一步.
4. 在index.html中, 添加一個按鈕, 關閉子進程
在index.html的<body>
和</body>
塊中的最下方, 添加如下代碼:
<button onclick="killChildProcess()">關閉子進程</button>
在這段代碼中, 我們添加了一個按鈕button
, 在網頁中按鈕顯示為關閉子進程
, 並給該按鈕綁定了一個函數killChildProcess()
.
5. 創建renderer.js, 並添加到項目中
在html目錄創建一個renderer.js文件
添加如下代碼:
function killChildProcess() {
// 發消息,由html的按鈕調用,給主進程發消息,回調中關閉進程
const ipcRenderer = require('electron').ipcRenderer;
ipcRenderer.send('kill-child-now', 'get async message');
}
我們定義了關閉子進程
按鈕的點擊函數killChildProcess()
, 這個函數只有兩行:
在函數的第一行, 創建了一個ipcRenderer
對象
const ipcRenderer = require('electron').ipcRenderer;
這個對象是通過ipcRenderer
模塊創建出來的, w3cschool是這樣解釋的:
ipcRenderer 模塊是一個 EventEmitter 類的實例. 它提供了有限的方法,你可以從渲染進程向主進程發送同步或異步消息. 也可以收到主進程的響應.
簡單的說, main.js是主進程
, renderes.js是渲染進程
, 在渲染進程調用ipcRenderer.send()
方法, 可以發送消息. 在主進程可以收到消息, 如果你給這個消息綁定了回調, 收到消息后, 就會觸發回調.
在函數的第二行, 我們發送了kill-child-now
消息.
現在我們把renderer.js引入到項目之中
和jquery
相似, 在index.html的<head>
和</head>
塊中, 添加如下代碼:
<script type="text/javascript" src="../dist/renderer.js"></script>
6. 在main.js中, 監聽消息, 綁定回調
在main.js的最下方, 添加如下代碼:
// 監聽消息, 關閉子進程
const ipcMain = require('electron').ipcMain;
ipcMain.on('kill-child-now', (e, appUrl)=>{
// 收到消息, 關閉進程
mySpawn.kill();
});
在這段代碼中:
我們創建了一個ipcMain
對象
const ipcMain = require('electron').ipcMain;
這個對象是通過ipcMain
模塊創建出來的, w3cschool是這樣解釋的:
ipcMain 模塊是類 EventEmitter 的實例.當在主進程中使用它的時候,它控制着由渲染進程(web page)發送過來的異步或同步消息.從渲染進程發送過來的消息將觸發事件.
簡單的說, ipcMain
是使用在主進程中的, 負責監聽從渲染進程中發送出來的消息.
( 還記得嗎? 渲染進程是通過ipcRenderer
發送消息的. )
我們用ipcMain對象監聽了消息kill-child-now
, 並且綁定了一個回調函數. 一旦收到這個消息, 就會觸發這個回調函數.
回調函數只有一行, 簡單直接:
mySpawn.kill( )
關閉在第三步中創建的子進程notepad++.
7. 啟動
執行命令:
npm start
和之前的測試一樣, 在程序啟動后, notepad++也緊跟着啟動了, notepad++就是本程序啟動的子進程.
不一樣的是, 程序界面上出現了一個按鈕關閉子進程
.
點擊這個按鈕試試看!