回顧請前往第一節
本文全部代碼均可以在github找到。你能夠經過commit歷史來查看這些代碼是如何一步一步構建的。若是有任何問題,也能夠在github的issue上提出。javascript
接前文,如今咱們搭建好了一系列的環境,建立了一些初始的代碼,是時候開始工做了。
在這篇文章中咱們主要負責建立登陸界面與主界面,涉及篇幅關係咱們再也不使用遠程服務端來交互,而是建立一些模擬的登陸請求,固然,與服務端的交互方法能夠在此係列文章後面幾篇找到。OK,這裏咱們但願前端可以像QQ或微信同樣,先展現一個登陸界面,在登陸成功後帶領咱們打開一個長時間停留的主界面,咱們先理清須要作那幾件事:html
在Angular中建立路由,包括登陸界面與主界面。前端
建立browser相關代碼,給登陸與跳轉提供通訊反饋。java
在登陸成功後咱們關閉登陸界面跳轉至主界面。node
因爲咱們安裝了angular-cli,因此每次建立各種文件時均可以經過cli的方式來解決,這很方便,也下降了Angular的學習成本,若是對此不明白,能夠看這裏的文檔。react
首先在src/app
的路徑下建立2個組件: login與main。好吧,你須要輸入ng g component login
來建立這個組件,但在以後咱們就再也不討論這些細節,我只會告訴該怎麼作一件事。git
其次咱們在src/app
的路徑下建立一個路由app.routing.ts
,咱們但願它能夠作好兩件事,根據URL進行頁面的導航,在沒有權限時對相應的導航進行保護。具體代碼能夠參照Angular的官方文檔,但我猜大家懶得看,代碼以下:github
import {NgModule} from '@angular/core' import {Routes, RouterModule} from '@angular/router' import {LoginComponent} from './login/login.component' import {MainComponent} from './main/main.component' export const appRoutes: Routes = [ {path: '', component: LoginComponent}, {path: 'login', component: LoginComponent}, {path: 'main', component: MainComponent} ] @NgModule({ imports: [RouterModule.forRoot(appRoutes)], exports: [RouterModule] }) export class AppRoutingModule { }
ok,這很簡單,和咱們熟悉的Angular1.x或react-route也沒有太大區別。可是要讓路由運行起來還要作兩件事,第一是將路由在app.module.ts中註冊,在module上掛載文件,Angular在編譯時纔會將文件引入進來,第二是在app.component.html中增長路由插座。數據庫
#### 2, 建立樣式與邏輯 express
如今,咱們爲前端頁面添加一些樣式與邏輯,這此的commit記錄在這裏,如今咱們須要爲登陸界面添加邏輯與路由保護。
登陸能夠提交用戶名與密碼用做驗證,這時候能夠藉助Angular的模板語法來快速的完成它們:
<div class="input-box"> <input type="text" #username> </div> <div class="input-box"> <input type="text" #password> </div> <button (click)="login(username.value, password.value)">登陸</button>
咱們但願全部嚴格的邏輯或涉及數據庫的問題都放在主進程解決,那麼確認登陸須要與electron主進程進行交互,以便於主進程來切換窗口。固然,在實際業務中你能夠選擇把服務器的交互放在Angular中來作,也能夠在electron發起一個request。如今咱們按下面幾步來操做:
在login組件文件夾下建立login.service.ts,別忘了將服務添加到組件的providers依賴項中!
在src/index.html
文件中添加var electron = require('electron')
,別忘了script標籤。
在src/app
下添加shared文件夾,用來存放一些共用的組件與邏輯。在這裏建立一個名爲ipc-renderer
的服務,並將它註冊到app.component.ts
中。具體代碼以下:
import {Injectable} from '@angular/core declare let electron:any; @Injectable() export class IpcRendererService { constructor (){} private ipcRenderer = electron.ipcRenderer on (message: string, done){ return this.ipcRenderer.on(message, done); } send (message: string, ...args){ this.ipcRenderer.send(message, args); } api (action: string, ...args) { this.ipcRenderer.send('api', action, ...args); return new Promise((resolve, reject) => { this.ipcRenderer.once(`${action}reply`, (e, reply, status) =>{ if (!reply){ return reject(status) } return resolve(reply) }) }) } dialog (action: string, ...args) { this.ipcRenderer.send('dialog', action, ...args); } sendSync (message: string, ...args){ return this.ipcRenderer.sendSync(message, arguments); } }
這裏咱們經過
ipcRenderer
與electron交互,ipc-renderer就是Angular中用來通訊的公共服務,這個服務模塊理論上共享的,並且咱們也只但願它被實例化一次,因此將它注入在app.component.ts
中。這樣每次子組件須要服務時沒必要在providers中標明它,而是直接在constructor中注入便可。這很重要,特別是你想要在一個類中保存一些即時的數據信息,但願只存在一個實例用來共享時頗有用。
能夠看出來,api這個方法是咱們增長的一個有意思的方法,這裏咱們能夠做出一些參數上的約定,便於監聽事件時作出更好的反饋。
#### 3, 監聽與反饋
這時,api的第一個參數被約定爲action,用於描述這個API事件的用途,每個API事件都會發起一次apiName+reply
的事件用於回覆。在Angular的公共服務中,咱們不妨先把它轉化爲咱們熟悉的Promise,再返回給每個具體的組件服務,固然你也能夠直接把它用做作fromEvent的Observable,但在這裏,咱們但願它看起來像是一個http服務,便於你們更好的理解它們工做的方式。
實際上,你能夠選擇一些成熟electron數據通訊庫或框架來解決這些複雜的問題,但在第一次請不要這樣作,這就像上手使用Rails同樣,雖然作的很快,但對你並無多少益處。
這裏有一些複雜,若是你但願對照當時的代碼來學習,能夠看這一次的commit。
ok,你們也能夠想象的到,如今要作的是在electron中新建一個事件接收器,處理一些邏輯而且將它們返回,在根文件夾下新建browser/ipc/index.js
而且填充基礎的代碼:
const {ipcMain} = require('electron') const api = require('./api') ipcMain.on('api', (event, actionName, ...args) =>{ const reply = (replayObj, status = 'success') =>{ event.sender.send(`${actionName}reply`, replayObj, status); } if (api[actionName]){ api[actionName](Object.assign({reply: reply}, event), ...args) } })
假設如今有一個browser/ipc/api
文件做爲處理器,以上代碼作的事情便是肯定一個Action,而且監聽事件,爲event合併一個名爲reply
的方法,用於返回數據。根據此,咱們再建立這個虛擬的browser/ipc/api
文件:
module.exports = { login: (e, user) =>{ // todo something e.reply({msg: 'ok'}) } }
怎麼樣?如今看起來一切都完成了!每次當咱們在loginService中調用this.ipcRendererService.api
時,相應的數據就會被傳達至對應的事件(看起來它更像一個路由)上,咱們在nodejs環境中作一些操做,好比儲存session,更新數據庫,抓取新聞,向遠程服務器發送一條信息等等。
最關鍵的是咱們也能用垂手可得的方式來獲得想要的數據,回覆數據也足夠簡單,e.reply({msg: 'ok'})
就像是express中的res.xxx({});
同樣,整個項目也變得井井有條。等到有一天咱們須要下載、上傳、顯示系統原生提示框、讀取一個文件等等之類的功能時,只須要將Action名替換一下,在api文件夾下新增幾段邏輯便可。
這一小節文章有些瑣碎和複雜,登陸成功與跳轉等等邏輯不妨放在下一節中再講。你們能夠嘗試閱讀github的源碼,考慮它有哪些問題是值得優化的。在後面幾節中,咱們再來討論如何優化這些邏輯。