碼文不易啊,轉載請帶上本文鏈接呀,感謝感謝 https://www.cnblogs.com/echoyya/p/14297176.html
一、從Hello Electron開始
-
創建一個空的文件夾,並創建入口
main.js文件,index.html內容文件, -
安裝
electron-
npm init -y:初始化配置文件 package.json
-
npm i electron
-
-
main.js 文件
-
引入模塊,創建應用
-
創建窗口
-
加載內容
-
打開調試工具(可選)
-
關閉窗口及應用監聽
-
-
執行文件
-
直接執行:electron main.js
-
默認執行:electron .
-
package.json 添加執行腳本: "start": "electorn main.js", 執行:
npm run start -
執行上述命令報錯解決:先可嘗試全局安裝,在執行命令,如若仍然報錯,可能需要配置腳本執行權限

windows下運行
*.ps1腳本(powershell的腳本)的時候,需要設置執行權限,PowerShell默認的執行策略就是Restricted,禁止任何腳本的執行。-
首先管理員身份運行 windows powershell ,輸入
Get-ExecutionPolicy,用於獲得當前的執行策略。 -
Set-ExecutionPolicy命令設置/更改執行策略,選擇RemoteSigned這個執行策略,這個策略既安全又可以執行本地編寫的腳本

-
// main.js 引入模塊
// app模塊:控制應用的生命周期
// BrowserWindow模塊: 創建瀏覽器窗口
const { app ,BrowserWindow} = require('electron');
// path模塊: node 的內置模塊,用於拼接路徑
const path = require('path');
// 1.初始化應用之后,會觸發監聽ready 事件
app.on('ready',ny_createWindow)
let win;
// 創建窗口
function ny_createWindow(){
// 1.1創建窗口
win = new BrowserWindow({
width:330,
height:355,
resizable:false, // 是否可改變寬高,默認true
movable:false, // 是否可拖拽,默認true
webPreferences: {
nodeIntegration: true, // 是否集成 Nodejs
enableRemoteModule: true, // 是否允許渲染進程 調用主進程模塊
}
// 1.為了在渲染進程中使用require(),還需要啟用 nodeIntegration 。
// 2.從v9版本開始,remote除非將 enableRemoteModule 設置為true,否則不允許在渲染進程中使用。
});
// 1.2 加載內容
// win.loadURL('http://www.baidu.com') // 遠程
// __dirname: 當前js文件所在的文件夾路徑,絕對路徑
win.loadURL(path.join(__dirname, './index.html')) // 本地 相對路徑
// mac 系統:需要拼接 file 協議
// path.join('file://',__dirname,'./index.html')
// 1.3 調試工具
win.webContents.openDevTools(); // webContents: 控制和渲染頁面的
// 1.4 關閉窗口, 關閉窗口前想做的事
win.on('close',function(){
win = null; // 關閉窗口
app.quit(); // 關閉應用
})

二、制作設置菜單 Menu
-
創建
menu.js,引入模板,創建菜單模板 -
構建菜單(實例化一個菜單對象)
-
設置菜單對象到應用中
-
用到的方法:
buildFromTemplate,setApplicationMenu -
選項:
- type:('normal' | 'separator' | 'submenu' | 'checkbox' | 'radio')
- label:標題
- accelerator:快捷鍵,區分 mac 及 win
- submenu:子菜單
- click:點擊事件
-
main.js中引用:
require('./menu');
// menu.js 引入模板
const { Menu } = require('electron')
// 1.設置一個模板
let template = [
{
label:'文件',
submenu:[
{
label:'新建文件',
accelerator:'ctrl+N',
click:function(){
console.log('new file')
}
},
{
type:'separator'
},
{
label:'新建窗口',
accelerator:(function(){
if(process.platform =='darwin'){ //mac 基於darwin
return 'alt+command+M'
}else{ //win
return 'alt+ctrl+M'
}
})(),
click:function(){
console.log('new window')
}
},
{
type:'separator'
},
{
label:'自動保存',
accelerator:'ctrl+S',
type:'checkbox',
checked:true,
click:function(){
console.log('saved')
}
},
]
},
{
label:'編輯'
},
]
// 2. 構建菜單(實例化一個菜單對象)
const menu = Menu.buildFromTemplate(template);
//3. 設置菜單對象到應用中
Menu.setApplicationMenu(menu);

三、主進程(Main Process)和渲染進程(Render Process)
electron核心可以分成2個部分,主進程和渲染進程。主進程連接着操作系統和渲染進程,可以看做頁面和計算機溝通的橋梁。渲染進程就是我們所熟悉前端環境了。只是載體改變了,從瀏覽器變成了window。傳統的web環境我們是不能對用戶的系統進行操作的。而electron相當於node環境,可以在項目里使用所有的node api 。
簡單理解:
給web項目套上一個node環境的殼。
主進程
在Electron中,入口是一個js文件,運行這個入口文件的進程稱作主進程。
(通常會是package.json里的main腳本,一般是main.js)
在主進程使用BrowserWindow模塊可以創建並管理web頁面,也就是應用的GUI(圖形界面)
const { BrowserWindow } = require('electron');
const path = require('path');
// 主進程創建web頁面
let win = new BrowserWindow({...});
// 加載本地文件
// win.loadURL(path.join('file://',__dirname, './index.html')) // mac
win.loadURL(path.join(__dirname, './index.html'))
渲染進程
在主進程創建的每一個web頁面也都運行着自己的進程,頁面引入的js文件就屬於渲染進程。
渲染進程各自管理自己的頁面,可以想象是瀏覽器的一個個的tab。

四、在渲染進程中創建一個子窗口
-
創建渲染進程對應
render.js文件 -
渲染進程引入
BrowserWindow模塊,需要借助於remote模塊,- 渲染進程不能直接使用 BrowserWindow ,因為該模塊默認是主進程允許使用的
- 借助 remote ,從中引入主進程中的模塊,需要在主進程窗口中配置
enableRemoteModule,允許渲染進程 調用主進程模塊
-
並在
index.html中引入render.js,兩種引入方法及區別
<!-- 1.引入render.js -->
<script src="./render-process/render.js"></script>
<!-- 2.electron 基於node -->
<script>
require('./render-process/render.js');
</script>
<--
區別:
src: 是全局變量
require: 引入的文件的最外層的變量,不是全局變量,注:為了在渲染進程中使用require(),還需在主進程窗口配置中啟用 nodeIntegration 。
//main.js
win = new BrowserWindow({
width:330,
height:355,
resizable:false, // 是否可改變寬高,默認true
movable:false, // 是否可拖拽,默認true
webPreferences: {
nodeIntegration: true, // 是否集成 Nodejs
enableRemoteModule: true, // 是否允許渲染進程 調用主進程模塊
}
})
使用:
1.元素綁定onclick事件 ==== src引入
2.require ==== 給元素綁定一個ID ,在render.js獲取元素並綁定事件
-->
五、進程間通信
在electron下,主進程與渲染進程相互通信要通過ipc(Inter-Process Communication),進程間通訊模塊來完成,
主進程與渲染進程調用的ipc模塊是不一樣的:
-
主進程調用
ipcMain -
渲染進程調用
ipcRenderer
A. 渲染進程 給 主進程 發送指令
-
ipcRenderer模塊:渲染進程引入,用於發送事件給主進程,和監聽主進程返回的回復事件-
const { ipcRenderer } = require('electron'); -
發送事件:
ipcRenderer.send('事件名稱',傳遞的數據); -
監聽事件:
ipcRenderer.on('監聽事件名稱',接收的數據);
-
-
ipcMain模塊:主進程引入,用於接收渲染進程發送的事件並進行回復-
const { ipcMain } = require('electron'); -
監聽事件:ipcMain.on('監聽事件名稱',接收的數據);
-
index.html:
<h1>Hello Electron!</h1>
<button onclick="ny_click()">click me</button>
<!-- 引入render.js 渲染進程-->
<script src="./render-process/render.js"></script>
render.js:
function ny_click(){
console.log('Render:','Echoyya')
ipcRenderer.send('myName','Echoyya');
}
main.js:
ipcMain.on('myName',function(event,msg){
console.log('Main:',msg);
})
運行結果:主進程輸出結果會打印在終端,而渲染進程輸出結果會打印在調試工具中

B. 主進程 給 渲染進程 發送指令
了解了 渲染進程 -> 主進程 后,反之就很好理解和掌握了,大同小異,簡單總結一下:
- main.js 發送指令 兩種方式:
ipcMain.on('myName',function(event,msg){
// 1. 通過event
//event.sender.send('msg-b','程序媛');
// 2. 通過webContents (推薦)
win.webContents.send('msg-b','程序媛');
})
- render.js 渲染進程接收指定
ipcRenderer.on('msg-b',function (event, msg) {
console.log('Render:',msg)
});
運行結果:

C. 渲染進程 給 渲染進程 發送指令
思路:渲染進程 -> 主進程 -> 渲染進程
a.js: ipcRenderer.send('dataToMain','渲染進程 -> 主進程 -> 渲染進程')
main.js:
ipcMain.on('dataToMain',function(event,data){
win.webContents.send('dataToRender',data);
})
b.js:
ipcRenderer.on('dataToRender', function (event, data) {
console.log(data)
})
D. 不同渲染進程之間數據共享
-
可以很簡單的使用H5的api來完成,如localStorage,sessionStorage,但今天要說的是另一種
-
在主進程中將一個對象儲存為全局變量,然后通過
remote模塊操作- 創建
a.js,b.js,並在index.html中引入
- 創建
index.html:
<button id="btn1">改變數據</button>
<button id="btn2">獲取數據</button>
<script>
require('./render-process/a.js');
require('./render-process/b.js');
</script>
main.js:
// 全局變量
global.shareObject = {
name:'上海'
}
a.js:
const remote = require('electron').remote;
let btn1 = document.getElementById('btn1');
btn1.onclick = function(){
remote.getGlobal('shareObject').name = '北京';
console.log('has changed');
}
b.js:
const remote = require('electron').remote;
let btn2 = document.getElementById('btn2');
btn2.onclick = function(){
let msg = remote.getGlobal('shareObject').name
console.log(msg)
}

六、提示框 dialog 模塊
-
首先dialog模塊是主進程可使用模塊
-
調用語法:
dialog.showMessageBox({ ... }),版本升級后不支持原來的回調方法,改為返回promise對象 -
常用配置對象參數:
- type:類型(error/info)
- title:標題
- message:提示信息
- icon:本地圖標(需使用nativeImage模塊,且主進程與渲染進程均可用該模塊)
- buttons:按鈕(數組類型)
const { dialog ,nativeImage} = require('electron');
const path = require('path');
// 1.信息對話框
dialog.showMessageBox({
title:'溫馨提示',
message:'XXXXX XXXXX XXXXX XXXXX XXXXX',
buttons:['Yes','No'],
icon:nativeImage.createFromPath(path.join(__dirname,'../src/img/icon1.png'))
}).then(function(index){
if(index.response == 0){ // 點擊了Yes按鈕
console.log('I want you !');
}else{ // 點擊了No按鈕
console.log('no no no');
}
});
// 2.錯誤提示框
dialog.showErrorBox('1213','訪問錯誤')

七、打包(electron-packager)
安裝打包工具:npm i electron-packager
打包必要元素及格式輸入:electron-packager <應用目錄> <應用名稱> <打包平台> --out=<輸出目錄> <架構> <應用版本> <忽略文件> <圖標> --overwrite
執行上述命令,可在輸出目錄中,打包成功一個exe 可執行文件,此命令區分mac及win,設備原因,此處僅演示win系統打包,mac系統的同學,需自行查找相關資料!!!
package.json:
"scripts": {
"start": "electorn main.js",
"pack":"electron-packager ./ test --platform=win32 --out=./dist --arch=x64 --app-version=1.0.0 --ignore=node_modules --icon=./src/img/hrbb.ico --overwrite "
},

