BehaviorSubject与 Subject 不同之处

需求

保持一个ShareModule不变,实现前台器具用户和计量机构注销功能

开始思路

1.增加一个实体
2.判断是器具用户登录,如果是则调用器具用户的注销,否则调用计量机构的注销(分别显示对应的菜单)

实现

创建一个对象,订阅之前的$isLogin 如果是true表示已登录,然后调用对应注销方法,实现代码如下:

    // tobar数组的第一对象的位置,改变位置时需改变profileMenuIndex
    private profileMenuIndex = 0;

    tobars: Tobar[] = [
        {
            title: 'Profile',
            class: 'fa fa-fw fa-user',
            state: false,
            onclickFn: () => {
                this.router.navigateByUrl('/main/personal');
            }
        },
        {
            title: 'Privacy',
            class: 'fa fa-fw fa-user-secret',
            state: true,
            onclickFn: () => {
            }
        },
        {
            title: 'Settings',
            state: true,
            class: 'fa fa-fw fa-cog',
            onclickFn: () => {
            }
        },
        {
            title: 'Logout',
            state: true,
            class: 'fa fa-fw fa-sign-out',
            onclickFn: () => {
                // 器具用户注销
                this.unsubscribeMain = this.departmentService.$isLogin.subscribe((isInstrumentUserLogin) => {
                    if (isInstrumentUserLogin) {
                        this.departmentLogout();
                    }
                });
                this.unsubscribeMain.unsubscribe();
                // 计量机构注销
                this.unsubscribeAdmin = this.systemService.$isLogin.subscribe((isAdminLogin) => {
                    if (isAdminLogin) {
                        this.logout();
                    }
                });
                this.unsubscribeAdmin.unsubscribe();
            }
        },
    ];

    ngOnInit(): void {
        this.departmentService.$isLogin.subscribe((isLogin) => {
            if (isLogin) {
                this.showProfileMenu();
            }
        });
    }
    
    // 改变state,true显示,false不显示
    showProfileMenu(): void {
        this.tobars[this.profileMenuIndex].state = true;
    }

然而并没有实现

问题: 计量机构的注销并不起作用
发现:我订阅的计量机构$isLogin不执行,所以说计量机构不能实现注销

clipboard.png

看了潘老师之前写的 $isLogin,发现俩个并不一样
private _$isLogin = new BehaviorSubject (false);
public $isLogin = new Subject ();

在此感谢张喜硕组长的帮忙!!

BehaviorSubjectSubject区别

  • Subject

创建一个Rxjs Subject, 数据的类型是number

let subject1: Subject = new Subject();

然后我们使用Subjectnext方法来emit(发射)1条数据

subject1.next(1);

接下来对subject1创建两个订阅,在subscription中直接打印接受到的数据

 subject1.subscribe((res: number) => console.info("subjectA ", res)); 
 subject1.subscribe((res: number) => console.info("subjectB ", res));

接下来我在发射两条数据

 subject1.next(2); 
 subject1.next(3);

结果

subjectA 2
subjectB 2
subjectA 3
subjectB 3

有时候我明明从数据源发射一个数据,但在订阅者拿到的值却是undefined或者null, 这就是因为订阅者是在数据源发射之后创建的,自然无法接收到数据了。
假如我们想在订阅者创建之后,无论什么时候都能拿到数据, 这应该怎么办呢? 那就要考虑使用BehaviourSubject了。

  • BehaviourSubject

创建一个BehaviorSubject, 默认值设为0. BehaviorSubject需要给个默认值
然后发射一条数据1,创建一个订阅者,再发射一条数据2,再创建一个订阅者,最后发射一条数据3。
代码如下:

let subject2: BehaviorSubject = new BehaviorSubject(0);
subject2.next(1);
subject2.subscribe((res: number) => console.info("behavior-subjectA ", res));
subject2.next(2);
subject2.subscribe((res: number) => console.info("behavior-subjectB ", res));
subject2.next(3);

结果

behavior-subjectA 1
behavior-subjectA 2
behavior-subjectB 2
behavior-subjectA 3
behavior-subjectB 3

由于BehaviorSubject是可以存储最后一条数据或者初始默认值的, 所以无论订阅者什么时候订阅到数据源subject2上, 都能接收到数据。
所以针对订阅者behavior-subjectA, 他订阅的时候,数据流里最后一条数据是1, 他能立即接收到。 然后依次能接收到最新的数据2和3。
针对订阅者behavior-subjectB, 他订阅的时候,数据流里最后一条数据是2, 他能立即接收到。 然后只能能接收到最新的数据3了。

上述来源Subject四种主题解析,四种Subject特点如下:

clipboard.png

回到上述问题

所以说在订阅者,订阅他的时候之前的数据他是接受不到的,所以就出现了上述问题,修改之后

clipboard.png

clipboard.png

虽然是实现了,但是潘老师说这样思路是不对的,如果俩个用户同时登录呢,然后我试了一下果然出现了问题,菜单也不是我想要的了(自己考虑的还是不够啊!!)

新的思路

clipboard.png

实现代码如下(及供参考):

  • share组件

app.tobar.service.ts

export class AppTobarService {

    constructor(public systemService: SystemService,
                public departmentService: DepartmentService,
                public router: Router) {
    }

    public $tobars = new BehaviorSubject([
        {
            title: 'Profile',
            class: 'fa fa-fw fa-user',
            onclickFn: () => {
            }
        },
        {
            title: 'Privacy',
            class: 'fa fa-fw fa-user-secret',
            onclickFn: () => {
            }
        },
        {
            title: 'Settings',
            class: 'fa fa-fw fa-cog',
            onclickFn: () => {
            }
        },
        {
            title: 'Logout',
            class: 'fa fa-fw fa-sign-out',
            onclickFn: () => {
            }
        },
    ]);
}

app.tobar.component.ts

ngOnInit(): void {
        this.appTobarService.$tobars.subscribe((tobars: Tobar[]) => {
            this.tobars = tobars;
        });
    }
  • main组件

tobar.service.ts

export class TobarService extends AppTobarService {

    getTobar(): any[] {
        return [
            {
                title: '个人中心',
                class: 'fa fa-fw fa-user',
                onclickFn: () => {
                    this.router.navigateByUrl('/main/personal');
                }
            },
            {
                title: '注销',
                class: 'fa fa-fw fa-sign-out',
                onclickFn: () => {
                    this.departmentService.loginOut();
                }
            },
        ];
    }
}

main.component.ts

ngOnInit() {
        // 初始化顶部菜 
        this.appTobarService.$tobars.next(this.tobarService.getTobar());
    }
  • admin组件

tobar.service.ts

export class TobarService extends AppTobarService {

    getTobar(): any[] {
        return [
            {
                title: '系统设置',
                class: 'fa fa-fw fa-cog',
                onclickFn: () => {
                    this.router.navigateByUrl('/admin/system');
                }
            },
            {
                title: '注销',
                class: 'fa fa-fw fa-sign-out',
                onclickFn: () => {
                    this.systemService.logout();
                }
            },
        ];
    }
}

admin.component.ts

ngOnInit() {
         // 初始化顶部菜单
        this.appTobarService.$tobars.next(this.tobarService.getTobar());
    }

总结

1.假设我之前的思路可行,但是在之后修改起来会很麻烦,增加一个菜单时会有很多不定的因素产生(加上时间问题,当时怎么写的已经不记得了,会产生不可控的错误)。

2.之后的思路,也就是潘老师说的一句话对扩展开放,对修改关闭,及时以后增加菜单,Share(模板)中永远保持不变(对修改关闭),想增加菜单只需改MainAdmin下的菜单就可以(对扩展开放)。

你可能感兴趣的:(typescript,angualr)