我可以在 Angular 中加载模板之前控制 Oninit() 吗?

Can i control about Oninit() before to load template in Angular?

这个问题我花了3天,我需要你的帮助

我的 Angular 项目中有 2 个关于 google 社交登录的问题。

  1. 刷新后保持用户登录(我使用 Google OAuth2)

  2. 第一次渲染时,我看不到登录按钮:(

我按照这个解决了第一个问题,但是我按照这个link解决了第一个问题,第二个问题仍然困扰着我

我认为我的项目有问题,在模板渲染后 oninit 函数完成。

此代码是我的 component.ts 文件。

export class NavbarComponent implements OnInit {

    log : boolean
    test : any
    googleAuth: any
    auth2 : gapi.auth2.GoogleAuth

  constructor(
        private ref : ChangeDetectorRef, 
        private http: HttpClient) { }

  async ngOnInit() {
        gapi.load('auth2', () => {
            gapi.auth2.init({
                client_id: 'MY_CLIENT_ID',
                scope : 'email',
            })
            .then((data) => {
                this.auth2 = data;
                this.googleAuth = gapi.auth2.getAuthInstance();
                this.log = this.handleAuthChange();
                this.googleAuth.isSignedIn.listen(this.handleAuthChange);
            })
        })
    }

    signIn = () => {
    this.auth2.signIn()
  };

  signOut = () => {
    this.auth2.signOut();
  };

    handleAuthChange = () => {
        return this.googleAuth.isSignedIn.get();
    }

我想做一个登录功能,使用onlu一键所以,我写了这样的模板代码。

<nav class="navbar-container">
    <a routerLink="/" class="main-icon-brand">
        <img src="../../assets/image/icon.png" alt="logo image" id="icon-image">
    </a>
    <a routerLink="/tutorial" class="each-item">
        <span>Tutorial</span>
    </a>
    <a routerLink="/making" class="each-item">
        <span>Making</span>
    </a>
    <a routerLink="/search" class="each-item">
        <span>Search</span>
    </a>
    <div id="navbar-space"></div>
    <div>
        <div *ngIf="log === false">
            <button (click)="signIn()" mat-icon-button color="warn">
                <mat-icon>account_circle</mat-icon>
            </button>   
        </div>
        <div *ngIf="log === true">
            <button (click)="signOut()"  mat-icon-button color="warn">
                <mat-icon>face</mat-icon>
            </button>   
        </div>
    </div>
</nav>

嗯...我想,这有两个解决方案

  1. 阻塞渲染模板直到完成 onInit
  2. 我尝试了 rxjs observable 但是,我的技能水平很低所以它不起作用( 也许,我对 rxjs 的概念有误)

我假设当您说首次呈现时看不到登录按钮时,您的意思是它加载有延迟。

这不是因为 ngOnInit() 运行 出了问题,而是因为您的 ngOnInit 创建了一个承诺,该承诺在其他一些生命周期完成后才会得到解决。 then(...) 子句中的代码仅在承诺已解决后运行。 Google Api 需要时间来执行您要求它执行的操作,因此您必须围绕它编写一些代码以使您的页面顺利加载。

这是一个大问题,但通常有几种方法可以处理等待 API 数据加载的问题。有些就像设计更改一样简单,以使加载看起来更顺畅。我认为有两种解决方案适合您,

  1. 重新考虑您在哪里检查他们是否已登录。您可以在应用程序根目录执行此操作,只需将登录状态传递给导航栏,这样您就不会每次加载导航栏时手动检查。这样您就可以更改加载和等待发生的位置。您可以在应用程序加载时访问 API,而不是在加载导航栏时,甚至可以将登录状态存储在您的状态中,以便您可以从应用程序中的任何位置访问它。

  2. 这是更快、更脏的解决方案,但您可以隐藏导航栏,直到它具有完全加载所需的所有数据。这个解决方案看起来像这样,

将您的整个导航栏模板包裹在此,

*ngIf="!(navbarLoading$ | async)"

然后在你的组件中,

public navbarLoading$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);

ngOnInit(): void {
        gapi.load('auth2', () => {
            gapi.auth2.init({
                client_id: 'MY_CLIENT_ID',
                scope : 'email',
            })
            .then((data) => {
                this.auth2 = data;
                this.googleAuth = gapi.auth2.getAuthInstance();
                this.log = this.handleAuthChange();
                this.googleAuth.isSignedIn.listen(this.handleAuthChange);
                this.navbarLoading$.next(false);
            })
        })
}