BehaviorSubject與 Subject 不一樣之處

需求

保持一個ShareModule不變,實現前臺器具用戶和計量機構註銷功能segmentfault

開始思路

1.增長一個實體
2.判斷是器具用戶登陸,若是是則調用器具用戶的註銷,不然調用計量機構的註銷(分別顯示對應的菜單)數組

實現

建立一個對象,訂閱以前的$isLogin 若是是true表示已登陸,而後調用對應註銷方法,實現代碼以下:app

// 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不執行,因此說計量機構不能實現註銷this

clipboard.png
clipboard.png

看了潘老師以前寫的 $isLogin,發現倆個並不同
private _$isLogin = new BehaviorSubject <boolean>(false);
public $isLogin = new Subject <boolean>();

在此感謝張喜碩組長的幫忙!!spa

BehaviorSubjectSubject區別

  • Subject

建立一個Rxjs Subject, 數據的類型是numbercode

let subject1: Subject<number> = new Subject<number>();

而後咱們使用Subjectnext方法來emit(發射)1條數據component

subject1.next(1);

接下來對subject1建立兩個訂閱,在subscription中直接打印接受到的數據router

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

接下來我在發射兩條數據對象

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

結果ip

subjectA 2
subjectB 2
subjectA 3
subjectB 3

有時候我明明從數據源發射一個數據,但在訂閱者拿到的值倒是undefined或者null, 這就是由於訂閱者是在數據源發射以後建立的,天然沒法接收到數據了。
假如咱們想在訂閱者建立以後,不管何時都能拿到數據, 這應該怎麼辦呢? 那就要考慮使用BehaviourSubject了。

  • BehaviourSubject

建立一個BehaviorSubject, 默認值設爲0. BehaviorSubject須要給個默認值
而後發射一條數據1,建立一個訂閱者,再發射一條數據2,再建立一個訂閱者,最後發射一條數據3。
代碼以下:

let subject2: BehaviorSubject<number> = new BehaviorSubject<number>(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下的菜單就能夠(對擴展開放)。

相關文章
相關標籤/搜索