初探Subject and Subscribe (Ionic4 Angular6)

56次阅读

共计 2321 个字符,预计需要花费 6 分钟才能阅读完成。

类似的东西很多,但是不得不说大部分资料中的例子不是难以理解就是形而上学,所以我想分享一点自己的代码来帮助更多初学者。
起源:我打算做一个弹出登录,里面包含一个注册按钮,点击注册则切换到弹出注册,当然在注册时也能切换回登录。在实现的过程中一路踩过以下的坑:

如果将一个 component/page 应用到 modal 中,那么这个 component/page 必须在不低于弹出 modal 的层级的 module.ts 文件中的 @NgModule 的 entryComponents 部分声明出来,不然会得到一个错误。
一个 component/page 只能在一个 module.ts 文件中声明
调用弹出方法的 ts 文件必须引用使用到的 component/page
如果两个 ts 文件中都同时引用了对方 (a.ts import b, b.ts impot a) 那么会得到一个循环依赖的警告,这不影响运行,但是看着闹心。

所以我要再次修改一下,避免这个警告,最后选择了 subject 的方案。
不要尝试直接复制运行,因为我去掉了和本文无关的部分,比如 import {Component} from ‘@angular/core’; 这样的语句。
首先在某个单例模式的 service 中加入如下代码:
import {Subject, Subscription} from ‘rxjs’;
// 公有属性 switchModel,这是一个可供订阅的主题
@Injectable({
providedIn: ‘root’
})
export class SiteService {
public switchModel: Subject<Object> = new Subject<Object>();
}
为了解决问题 4,所以弹出的行为将仅在 app.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 做类似的处理
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 更新的消息时会根据最新的消息做出适当的处理。
理论上来说,我们可以创建一个全局的主题,每个订阅者都可以通过消息的数据类型或其它特征决定自己如何处理,但是个人还是喜欢定制主题从而减少订阅。
刚接触 Angular6 不久,不管是我这个想法本身有错误还是解决的方式有问题都请拍砖不要客气,只求大侠的砖头上绘制一下示例代码,不胜感激。

正文完
 0