初探Subject and Subscribe (Ionic4 Angular6)

相似的東西不少,可是不得不說大部分資料中的例子不是難以理解就是形而上學,因此我想分享一點本身的代碼來幫助更多初學者。app

起源:我打算作一個彈出登陸,裏面包含一個註冊按鈕,點擊註冊則切換到彈出註冊,固然在註冊時也能切換回登陸。在實現的過程當中一路踩過如下的坑:ionic

  1. 若是將一個component/page應用到modal中,那麼這個component/page必須在不低於彈出modal的層級的module.ts文件中的@NgModule的entryComponents部分聲明出來,否則會獲得一個錯誤。
  2. 一個component/page只能在一個module.ts文件中聲明
  3. 調用彈出方法的ts文件必須引用使用到的component/page
  4. 若是兩個ts文件中都同時引用了對方(a.ts import b, b.ts impot a)那麼會獲得一個循環依賴的警告,這不影響運行,可是看着鬧心。

因此我要再次修改一下,避免這個警告,最後選擇了subject的方案。ide

不要嘗試直接複製運行,由於我去掉了和本文無關的部分,好比import { Component } from '@angular/core';這樣的語句。this

首先在某個單例模式的service中加入以下代碼:code

import { Subject, Subscription } from 'rxjs';
//公有屬性switchModel,這是一個可供訂閱的主題
@Injectable({
  providedIn: 'root'
})
export class SiteService {
    public switchModel: Subject<Object> = new Subject<Object>();
}

爲了解決問題4,因此彈出的行爲將僅在app.component上發生component

import { ModalController } from '@ionic/angular';
import { SiteService } from '../services/site/site.service'; //自行替換爲聲明瞭subject的service
import { LoginComponent } from '../login/login.component'; //自行替換爲你要彈出的內容1
import { SignupComponent } from '../signup/signup.component'; //自行替換爲你要彈出的內容2
/*
若是有的話你能夠添加更多的內容
注意確認它們被正確的聲明在entryComponents部分
對於app.component.ts,其對應的module必然是app.module.ts
*/
export class AppComponent {
    constructor(
        private modalController: ModalController,
        private siteService: SiteService
    ){
        this.siteService.switchModel.subscribe(option => {
            this._switchModel(option);
        });
    }
    private _switchModel(option) {
      let component = null;
      switch(option.componentName) {
          case 'LoginComponent':
              component = LoginComponent;
              break;
          case 'SignupComponent':
              component = SignupComponent;
              break;
          case '': //若是沒有指定component那就是直接關閉咯,這是爲了在component內部能省掉引用ModalController和關閉modal的代碼
              break;
          default:
              return; //這件事和我無關,跳過。防止對其它subscriber負責的component重複處理
      }
      this.modalController.dismiss().then(() => {
          this.modalController.create({
              component: component,
              componentProps: option.params || null
          }).then(modal => modal.present());
      });
    }
}

而後在LoginComponent爲註冊按鈕添加一個事件,SignupComponent作相似的處理rxjs

import { SiteService } from '../services/site/site.service';
export class LoginComponent implements OnInit {
    doSwitch() {          
        this.siteService.switchModel.next({
            componentName: 'SignupComponent'
        });
    }
    cancel() {
        this.siteService.switchModel.next({
            componentName: ''
        });
    }
}

邏輯描述:LoginComponent調用Subject的next方法同時傳遞數據,這樣Subject就會將該數據通知到訂閱者(AppComponent訂閱了這個subject),AppComponent在獲得Subject更新的消息時會根據最新的消息作出適當的處理。事件

理論上來講,咱們能夠建立一個全局的主題,每一個訂閱者均可以經過消息的數據類型或其它特徵決定本身如何處理,可是我的仍是喜歡定製主題從而減小訂閱。ip

剛接觸Angular6不久,無論是我這個想法自己有錯誤仍是解決的方式有問題都請拍磚不要客氣,只求大俠的磚頭上繪製一下示例代碼,不勝感激。it

相關文章
相關標籤/搜索