一、項目技術(shù)棧:Electron+react+react-router+antd
1、Electron:electron是一個使用js,html和css等的web技術(shù)創(chuàng)建原生桌面應(yīng)用的框架,他基于chromium和node.js,構(gòu)建的應(yīng)用可以在Mac,windows和Linux三個平臺上運行。
2、React和react-router在該項目中負責構(gòu)建單頁面應(yīng)用和路由跳轉(zhuǎn)的實現(xiàn)。
3、Antd作為UI框架。
二、項目搭建
1、創(chuàng)建一個react項目
我們使用目前已經(jīng)比較成熟的create-react-app腳手架來創(chuàng)建一個react項目,關(guān)于這個腳手架的更多資料可以查看:https://facebook.github.io/create-react-app/docs/getting-started。
這里我們使用如下的命令:
npx create-react-app my-app
cd my-app
npm start
如果成功,此時可以打開瀏覽在http://localhost:3000/上會運行著我們新建的項目。
可以通過npm run eject 彈出內(nèi)建,方便看出有哪些安裝的依賴。
2、引入electron
npm i electron --save-dev
安裝成功后還不能直接運行一些命令,需要先進行一些配置,至少要有個electron需要用到的main.js入口文件(根目錄下)。
3、配置
①在package.json中配置入口文件,具體如下:

修改啟動命令:

這里的dev想要同時執(zhí)行兩個命令,使用了|將兩個命令分開。
其中electron . --debug ,是調(diào)試命令需要運行項目同時開啟開發(fā)者工具,入口文件中會對這個命令進行判斷,并開啟指定工具。
②main.js文件的編寫
(復(fù)制github上electron的demo項目中的main.js做一些修改)
如下是當前全部的main.js內(nèi)容
const { app, BrowserWindow } = require('electron');
const path = require('path');
let mainWindow = null;
//判斷命令行腳本的第二參數(shù)是否含--debug
const debug = /--debug/.test(process.argv[2]);
function makeSingleInstance () {
if (process.mas) return;
app.requestSingleInstanceLock();
app.on('second-instance', () => {
if (mainWindow) {
if (mainWindow.isMinimized()) mainWindow.restore()
mainWindow.focus()
}
})
}
function createWindow () {
const windowOptions = {
width: 400,
height: 300,
frame:false,
};
mainWindow = new BrowserWindow(windowOptions);
mainWindow.loadURL("http://localhost:3000/");
// mainWindow.loadURL(path.join('file://', __dirname, '/build/index.html'));
//接收渲染進程的信息
const ipc = require('electron').ipcMain;
ipc.on('min', function () {
mainWindow.minimize();
});
ipc.on('max', function () {
mainWindow.maximize();
});
ipc.on("login",function () {
mainWindow.maximize();
});
//如果是--debug 打開開發(fā)者工具,窗口最大化,
if (debug) {
mainWindow.webContents.openDevTools();
require('devtron').install();
}
mainWindow.on('closed', () => {
mainWindow = null
})
}
makeSingleInstance();
//app主進程的事件和方法
app.on('ready', () => {
createWindow();
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
});
app.on('activate', () => {
if (mainWindow === null) {
createWindow();
}
});
module.exports = mainWindow;
如上,注意將主進程的loadUrl設(shè)置為localhost:3000,這樣可以展示運行在這個地址下的頁面。
③安裝配置devtron插件
使用如下命令安裝:
npm i devtron --save-dev
安裝好后:在main.js中進行配置,參考上面main.js文件中的注釋。
四、進程通信
項目構(gòu)建完成后,這里開始講解一下,react的項目和electron結(jié)合使用中的一個應(yīng)用問題。先把需求提出來,如下圖,我們需要在頁面中點擊右上角最小化時將頁面窗口最小化(點擊×?xí)r的功能以此類推),當點擊登錄時修改窗口大小,并展示直播頁面。

要完成這個功能,要使用到Electron的API,這就要先從electron應(yīng)用結(jié)構(gòu)來說起,electron結(jié)構(gòu)中分為主進程和渲染器進程,如下是electron官網(wǎng)的一段話。

意思就是說,main.js就是主進程,在主進程中打開的一個web頁面就是一個渲染進程,這個web頁面也就是該項目中的這個index.html,并且可以直接web頁面上通過nodejs的api進行系統(tǒng)級的交互。
如果我們沒有使用react,那么沒有什么問題,但是在react引入electron就會報錯了。所以,要在react中使用,就需要提前將electron賦值給window.electron 以方便使用。在index.html的head中增加了一句js,如下圖:
<script>global.electron = require('electron')</script>
此時,回想一下需求,點擊“—”時最小化,我們發(fā)現(xiàn)觸發(fā)事件的ui在web頁面(react組件)中,而想要操作的mainWindow對象(主進程中打開的那個頁面)卻在主進程中。所以,嘗試一個解決方案,讓web頁面(react組件)和主進程進行通信。
實現(xiàn)進程通信使用到的api有ipcRenderer和ipcMain.
具體運用如下:
import React from 'react';
import { Layout,Icon } from 'antd';
import "./UserLayout.scss";
import UserRouter from "../../router/userRouter";
const {ipcRenderer} = window.electron;
class UserLayout extends React.Component{
closeWindow=()=>{
window.close();
};
minWindow=()=>{
ipcRenderer.send("min");
};
render(){
return(
<div className="login">
<div className="top">
<div className="top-right">
<Icon type="minus" style={{margin:"0 8px"}} onClick={this.minWindow}/>
<Icon type="close" onClick={this.closeWindow}/>
</div>
<div className="top-center">
云直播
</div>
</div>
<div className="main">
<div className="main-content">
{UserRouter()}
</div>
</div>
</div>
)
}
}
export default UserLayout;
如上點擊時執(zhí)行minWindow,引入ipcRender發(fā)送一個消息”min”,main.js中有對應(yīng)的ipcMain進行監(jiān)聽,請看如下:
//接收渲染進程的信息
const ipc = require('electron').ipcMain;
ipc.on('min', function () {
mainWindow.minimize();
});
因此,主進程收到消息后,即可對窗口進行處理為最小化,而登錄功能與此類似,傳遞消息到主進程同時跳轉(zhuǎn)頁面,主進程收到消息后執(zhí)行窗口最大化,因此就實現(xiàn)了最初的需求。
同理,當組件有其他操作需要主進程作出反饋時,也可以使用此方案。