初探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

相关文章
相关标签/搜索