一芹橡、項(xiàng)目技術(shù)棧:Electron+react+react-router+antd
1韩玩、Electron:electron是一個(gè)使用js佑吝,html和css等的web技術(shù)創(chuàng)建原生桌面應(yīng)用的框架骨饿,他基于chromium和node.js围段,構(gòu)建的應(yīng)用可以在Mac顾翼,windows和Linux三個(gè)平臺(tái)上運(yùn)行。
2奈泪、React和react-router在該項(xiàng)目中負(fù)責(zé)構(gòu)建單頁(yè)面應(yīng)用和路由跳轉(zhuǎn)的實(shí)現(xiàn)适贸。
3灸芳、Antd作為UI框架。
二拜姿、項(xiàng)目搭建
1烙样、創(chuàng)建一個(gè)react項(xiàng)目
我們使用目前已經(jīng)比較成熟的create-react-app腳手架來(lái)創(chuàng)建一個(gè)react項(xiàng)目,關(guān)于這個(gè)腳手架的更多資料可以查看:https://facebook.github.io/create-react-app/docs/getting-started蕊肥。
這里我們使用如下的命令:
npx create-react-app my-app
cd my-app
npm start
如果成功谒获,此時(shí)可以打開(kāi)瀏覽在http://localhost:3000/上會(huì)運(yùn)行著我們新建的項(xiàng)目。
可以通過(guò)npm run eject 彈出內(nèi)建晴埂,方便看出有哪些安裝的依賴究反。
2、引入electron
npm i electron --save-dev
安裝成功后還不能直接運(yùn)行一些命令儒洛,需要先進(jìn)行一些配置精耐,至少要有個(gè)electron需要用到的main.js入口文件(根目錄下)。
3琅锻、配置
①在package.json中配置入口文件卦停,具體如下:
修改啟動(dòng)命令:
這里的dev想要同時(shí)執(zhí)行兩個(gè)命令,使用了|將兩個(gè)命令分開(kāi)恼蓬。
其中electron . --debug ,是調(diào)試命令需要運(yùn)行項(xiàng)目同時(shí)開(kāi)啟開(kāi)發(fā)者工具惊完,入口文件中會(huì)對(duì)這個(gè)命令進(jìn)行判斷,并開(kāi)啟指定工具处硬。
②main.js文件的編寫(xiě)
(復(fù)制github上electron的demo項(xiàng)目中的main.js做一些修改)
如下是當(dāng)前全部的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'));
//接收渲染進(jìn)程的信息
const ipc = require('electron').ipcMain;
ipc.on('min', function () {
mainWindow.minimize();
});
ipc.on('max', function () {
mainWindow.maximize();
});
ipc.on("login",function () {
mainWindow.maximize();
});
//如果是--debug 打開(kāi)開(kāi)發(fā)者工具小槐,窗口最大化,
if (debug) {
mainWindow.webContents.openDevTools();
require('devtron').install();
}
mainWindow.on('closed', () => {
mainWindow = null
})
}
makeSingleInstance();
//app主進(jìn)程的事件和方法
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;
如上荷辕,注意將主進(jìn)程的loadUrl設(shè)置為localhost:3000凿跳,這樣可以展示運(yùn)行在這個(gè)地址下的頁(yè)面。
③安裝配置devtron插件
使用如下命令安裝:
npm i devtron --save-dev
安裝好后:在main.js中進(jìn)行配置疮方,參考上面main.js文件中的注釋控嗜。
四、進(jìn)程通信
項(xiàng)目構(gòu)建完成后骡显,這里開(kāi)始講解一下疆栏,react的項(xiàng)目和electron結(jié)合使用中的一個(gè)應(yīng)用問(wèn)題。先把需求提出來(lái)惫谤,如下圖壁顶,我們需要在頁(yè)面中點(diǎn)擊右上角最小化時(shí)將頁(yè)面窗口最小化(點(diǎn)擊×?xí)r的功能以此類(lèi)推),當(dāng)點(diǎn)擊登錄時(shí)修改窗口大小溜歪,并展示直播頁(yè)面博助。
要完成這個(gè)功能,要使用到Electron的API痹愚,這就要先從electron應(yīng)用結(jié)構(gòu)來(lái)說(shuō)起富岳,electron結(jié)構(gòu)中分為主進(jìn)程和渲染器進(jìn)程,如下是electron官網(wǎng)的一段話拯腮。
意思就是說(shuō)窖式,main.js就是主進(jìn)程,在主進(jìn)程中打開(kāi)的一個(gè)web頁(yè)面就是一個(gè)渲染進(jìn)程动壤,這個(gè)web頁(yè)面也就是該項(xiàng)目中的這個(gè)index.html铛绰,并且可以直接web頁(yè)面上通過(guò)nodejs的api進(jìn)行系統(tǒng)級(jí)的交互桶蛔。
如果我們沒(méi)有使用react,那么沒(méi)有什么問(wèn)題,但是在react引入electron就會(huì)報(bào)錯(cuò)了皆辽。所以,要在react中使用臣樱,就需要提前將electron賦值給window.electron 以方便使用训枢。在index.html的head中增加了一句js,如下圖:
<script>global.electron = require('electron')</script>
此時(shí)醉旦,回想一下需求饶米,點(diǎn)擊“—”時(shí)最小化,我們發(fā)現(xiàn)觸發(fā)事件的ui在web頁(yè)面(react組件)中车胡,而想要操作的mainWindow對(duì)象(主進(jìn)程中打開(kāi)的那個(gè)頁(yè)面)卻在主進(jìn)程中檬输。所以,嘗試一個(gè)解決方案匈棘,讓web頁(yè)面(react組件)和主進(jìn)程進(jìn)行通信丧慈。
實(shí)現(xiàn)進(jìn)程通信使用到的api有ipcRenderer和ipcMain.
具體運(yùn)用如下:
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;
如上點(diǎn)擊時(shí)執(zhí)行minWindow,引入ipcRender發(fā)送一個(gè)消息”min”,main.js中有對(duì)應(yīng)的ipcMain進(jìn)行監(jiān)聽(tīng),請(qǐng)看如下:
//接收渲染進(jìn)程的信息
const ipc = require('electron').ipcMain;
ipc.on('min', function () {
mainWindow.minimize();
});
因此主卫,主進(jìn)程收到消息后逃默,即可對(duì)窗口進(jìn)行處理為最小化,而登錄功能與此類(lèi)似队秩,傳遞消息到主進(jìn)程同時(shí)跳轉(zhuǎn)頁(yè)面笑旺,主進(jìn)程收到消息后執(zhí)行窗口最大化,因此就實(shí)現(xiàn)了最初的需求馍资。
同理筒主,當(dāng)組件有其他操作需要主進(jìn)程作出反饋時(shí),也可以使用此方案鸟蟹。