Angular와 TypeScript를 사용하여 Electron 응용 프로그램 구축(3)

앞문장을 잇다.현재 우리는 Angular와 Electron의 상호작용을 완성했고 렌더링 프로세스에서 진행되는 모든 동작은 메인 프로세스 분석 저장소에 신속하게 보내고 피드백을 받을 수 있으며 렌더링 프로세스는 피드백에 따라 합리적인 대응을 할 수 있다.
오늘 우리는 로그인과 메인 프로세스의 상호작용을 위한 나머지 기능 모듈을 완성해야 한다.

이벤트 다시 로드 창


응답 이벤트를 통해 창 대상을 교체해야 하기 때문에 최소한 창 대상의 함수가 필요합니다. 물론 이 함수들은 서비스로 추출되어야 합니다.그 다음에 우리는 창 대상의 핸들 저장과 회수를 고려하고 대상을 바꾸거나 적당한 때에도 창 대상의 핸들을 변경해야 한다. 이를 감안하여 원 코드를 바탕으로 공용 클래스를 설계할 수 있다.
당분간 이 작업 창의 대상의 클래스를 Screen (일부는 유행에 맞지 않지만 window와 구분해야 함) 이라고 부른다. 루트 디렉터리에 있는 index에 의해 구분될 수 있다.js 호출은 모든api 함수에서 사용할 수 있습니다. 즉, 어쨌든 Screen은 하나의 실례만 있어야 창 대상의 핸들이 메모리에 캐시되어 호출자가 조작할 수 있습니다.
앞에서 우리가 쓴 index와 결합하다.js 파일은 이 Screen 클래스를 다시 한 번 생각해 봅시다. 창의 최대화, 최소화, 닫기, 활성화 등 작업에 응답하는 수동적인 방법이 필요합니다. 이런 작업은 고정된 매개 변수의 함수로 추상화될 수 있기 때문에 Screen 클래스에 정적 방법을 추가할 것입니다.구체적으로 다음과 같다.
// browser/screen/login.js
const {app, BrowserWindow} = require('electron')

module.exports = new class Login {
    constructor (){
    }

    open (url){
        const win = new BrowserWindow({
            width: 700,
            height: 500,
            show: false,
            frame: false,
            resizable: true
        });
        win.loadURL(url)
        win.webContents.openDevTools()
        return win
    }
}()

login 창을 여는 데 사용되는 Login 클래스를 만듭니다. 마찬가지로 이 코드를 복사해서 이름을 console 클래스로 바꾸고 제어판을 열 수 있습니다.이것은 파라미터 URL을 받아들여 윈도우 대상을 만들고 불러오는 몇 가지 특징이 있습니다. 마지막으로 이 윈도우 대상을 외부에 사용하도록 되돌려줍니다.주의해야 할 것은loadURL의 값을 전달하거나 루트 디렉터리의 index를 저장할 전역 변수를 지정하는 것입니다.js의 __dirname 는 경로를 간소화하는 데 사용되며, 다음에 우리는 다른 일을 해야 한다.
이제 Screen 클래스를 만들 수 있습니다.
// browser/screen/index.js
const login = require('./login')
const console = require('./console')
const windowList = {
    login: login,
    console: console
}

module.exports = new class Screen {
    constructor (){
        this.win = null
        this.baseUrl = ''
    }
    static show (win){
        win.show()
        win.focus()
    }

    //    
    open (winName = 'login'){
        if (!windowList[winName]) return ;
        this.win = windowList[winName].open(this.baseUrl)

        this.win.on('closed', () => this.win = null)
        this.win.on('ready-to-show', () => Screen.show(this.win))
    }
    setBaseUrl (baseUrl){
        this.baseUrl = baseUrl
        return this
    }
    
    activate (){
        this.win === null&& this.open()
    }
}()
windowList는 입력된 이름이 유효한지 검사하는 데 사용된다. 이 단계는 좀 쓸데없는 것 같지만 좋은 프로그래밍 습관을 잃지 않는다. 여러 사람이 협업하는 과정에서 당신은 자신의 코드를 계속 보완하는 동시에 다른 사람을 위해 오류를 피할 수 있다.수비형 프로그래밍과 유사하다.setBaseUrl는 바로 우리가 방금 언급한 저장__dirname에 사용된 함수다.화면 전체가 완성된 것 같습니다. 루트 디렉터리에 있는 index로 돌아가겠습니다.js 최적화:
//  index.js
const {app, BrowserWindow} = require('electron')
const screen = require('./browser/screen')
require('./browser/ipc/index')
const url = `file://${__dirname}/dist/index.html`

app.on('ready', _ => screen.setBaseUrl(url).open())
app.on('window-all-closed', _ => process.platform !== 'darwin'&& app.quit())
app.on('activate', _ => screen.activate())

어때요?이제는 그럴듯해 보입니다. ipc/api의 구체적인 파일에서 screen.open('console')만 사용하면 새 창을 열 수 있고, Angular 측은 알림을 받은 후에도 경로를 바꾸어 새로운 페이지를 책임집니다.이것은 하나의 예로 모두가 응용의 작업 방식을 이해하도록 도와준다. 생산 환경에서 당신은 먼저 성숙한 프레임워크나 라이브러리를 사용하여 이런 문제들을 해결해야 한다. 예를 들어electron-router이다.

다시 불러오는 창 재구성


현재 몇 가지 작은 문제가 있습니다. 로그인에 성공한 후에 Electron에 새 창을 열어 드리겠습니다. 그러나 어쨌든 이것은 우아하지 않은 해결 방안입니다. 새 창이 뜨는 것은 원래의 창이 순간적으로 사라져야 한다는 것을 의미하며, 로그인을 종료할 때 다시 새로운 로그인 창을 열어야 합니다.우리는 기존의 업무 논리에 대해 업데이트를 해서 루트의 제어를 Angular 자신에게 되돌릴 수 있으며, Electron은 적당한 시기에 창의 크기와 위치를 합리적으로 변화시킬 수 있다.이제 Screen 클래스에 대한 메서드를 추가합니다.
// browser/screen/index.js
// ......
setSize (w, h){
        if (this.win){
            const bounds = this.win.getBounds();
            const newBounds = {
                x: bounds.x - (w - bounds.width)/2,
                y: bounds.y - (h - bounds.height)/2
            }
            this.win.setBounds({
                x: newBounds.x,
                y: newBounds.y,
                width: w,
                height: h
            }, true)
        }
    }

set Size 방법이라고 불리지만 실제로 우리는 윈도우의bounds를 변경했다. 이것은 합리적이다. 우리는 항상 간단한 방법을 외부에 폭로했다. 설령 여기에서 몇 가지 일을 했지만 이것은 파라미터의 영향을 받지 않는 변화이다.창이 바뀔 때마다 합리적인 위치를 찾을 수 있습니다. 호출자에게는 setSize에 해당합니다.이 함수를 최적화하는 데 급급하지 마라. 다음에 우리는 설정 파일과 캐시 문제를 어떻게 해결하는지 토론할 것이다. 그러면 사용자의 습관 설정을 함수에 가져와서 메인 인터페이스가 매번 열린 위치와 지난번에 닫힌 위치가 일치하도록 하면 된다.심지어 우리는 Angular에 세션 식별 루트 점프 기능을 추가해야 한다.
지금/browser/ipc/api/index.js이 우리에 의해 다시 바뀌었다. 이렇게:
const screen = require('../../screen')

module.exports = {
    login: (e, user) =>{
        // todo something
        screen.setSize(1000, 720)
        e.reply({msg: 'ok'})
    }
}

모든 것이 순조롭고 MAC에서 창의 변화는 애니메이션 효과도 있다. 멋지지 않니?그리고 가장 합리적인 위치를 찾을 수 있어 성숙한 응용처럼 보인다.이제 Angular 애플리케이션에 변화를 주었습니다.

Angular 이벤트 구독


비록 우리가 Promise로 이 일들을 빨리 해결할 수 있지만, 이왕 배우기 시작한 이상 신기술을 좀 이해해도 무방하다.Rx.js는 아주 재미있는 거예요.아마도 많은 친구들이 다른 언어의 Reactive 모드를 들어본 적이 있을 것이다. 이해하기도 어렵지 않다. 만약 당신이 이 명사를 처음 들었다면 먼저 이 몇 개의 문서를 살펴보자. 공식 문서 번역은 또 다른 괜찮은 번역이다.
하나의 Promise를 Observable로 바꾸는 것은 매우 간단합니다. 당신은 간단하게 Rx를 바꿀 수 있습니다.js는 함수식 프로그래밍으로 이벤트를 조작하는 라이브러리로 이해합니다.
// src/app/login/login.service.ts
import {Injectable} from '@angular/core'
import {IpcRendererService} from '../shared/service/ipcRenderer'
import {Observable} from 'rxjs/Observable'
import 'rxjs/Rx'

@Injectable()
export class LoginService {

    constructor (
        private ipcRendererService: IpcRendererService
    ){
    }

    login (user: any): Observable {
        return Observable.fromPromise(this.ipcRendererService.api('login', user))
    }

}

여기fromPromise만 있으면 Promise를 Observable로 빠르게 전환할 수 있습니다.component에서 이전과 같이subscribe로 이 흐름을 구독하면 됩니다.fromPromise를 보면 from Event,from Callback 같은 것이 있을 수 있다고 생각할 수 있습니다. 사실 이것들은 모두 Rx의 정적 조작부호에 속합니다. 간단하게 말하면 모두 Observable 클래스의 static 방법일 뿐입니다.맵/filter/first를 사용할 때, Observable 클래스의 실례적인 방법만 호출합니다. 이 실례적인 방법들은this로 되돌아오기 때문에 끊임없이 체인식으로 호출할 수 있습니다.네가 좋아하기만 한다면, 너는 그것을 위해 각종 방법을 추가할 수 있으며, 심지어는 자신의 실례적인 방법을 Observable 클래스에 마운트할 수도 있다.구체적으로 Rx의 원본 코드를 보고 연구해 보십시오.
현재 우리는 거의 가장 이해하기 어려운 부분을 완성했고, 다음 몇 절에서 파충 코드와 인터페이스 전시 논리를 구축하기 시작했다.만약 당신도 동기화된 구축 코드를 가지고 있다면, 이 소절에 대해 궁금한 것이 있으면, 이번commit을 참고하여 해결할 수 있습니다.

좋은 웹페이지 즐겨찾기