網站搜尋

javascript - 為什麼 'emit' 只在我第一次點擊按鈕時顯示名稱?


我想使用 eventemiter 在點擊按鈕時傳送一個名字,但不工作。第一次點擊按鈕時名字沒有顯示,但如果再點擊一次,名字就會出現。https://stackblitz.com/edit/angular-ue9dzk-extrange-emit

app.component.html

<hello *ngIf="name"></hello>
<show></show>

app.component.ts

import { Component } from '@angular/core';
import { NameService } from './name.service';


@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
})
export class AppComponent  {
  name: string;
  constructor(private nameService: NameService) {

  }

  ngOnInit() {
    this.nameService.show.subscribe(name => {
      this.name = name;
    })
  }
}

hello.component.ts

import { Component, Input } from '@angular/core';
import { NameService } from './name.service';

@Component({
  selector: 'hello',
  template: `<h1>Hello {{name}}!</h1>`,
  styles: [`h1 { font-family: Lato; }`]
})
export class HelloComponent  {
  name: string;
  constructor(private nameService: NameService) {

  }

  ngOnInit() {
    this.nameService.show.subscribe(name => {
      this.name = name;
    })
  }
}

name.service.ts

import {EventEmitter} from '@angular/core';

export class NameService {
  show = new EventEmitter();
}

show.component.ts

import { Component, Input } from '@angular/core';
import { NameService } from './name.service';

@Component({
  selector: 'show',
  template: `<button (click)="show()">Click to emit</button>`,
  styles: [`h1 { font-family: Lato; }`]
})
export class ShowComponent  {
  name: string;
  constructor(private nameService: NameService) {

  }

  show() {
    this.nameService.show.emit('World');
  }

}

答案#1

EventEmitter 是用於 @Output() 綁定的,因為它可以選擇非同步地發出值。不要在共享服務中使用它。

<hello *ngIf="name"></hello>

上述 會在值被發出時建立 元件。值被發出後,元件將訂閱該服務,但 EventEmitter 不會保留先前發出的值的歷史紀錄。因此元件不會接收到任何東西。

參見建構函式:

https://angular.io/api/core/EventEmitter#constructor

你很少需要這個功能,但在某些情況下,@Output() 綁定需要在下一個變更檢測週期中發出一個值。因此在這些情況下你需要使用 EventEmitter,但你也可以使用其他 Observable 主體作為綁定的發射器。

但是如果再點擊一次,名字就會出現

元件建立後,它會接收發出的值,而當你第二次點擊按鈕時,會發出第二個值,該值會顯示在元件的範本中。

大多數創建共享服務的人會使用帶有預設值的 BehaviorSubject,或者如果需要等待直到可以發出值,則使用 ReplaySubject。

在上面的例子中,你有這個邏輯 *ngIf="name",這表示你想要 等待直到一個值被發出。所以你會使用 new ReplaySubject(1) 取代 EventEmitter。

export class NameService {
  show = new ReplaySubject(1);
}

答案#2

那是因為你在 hello 應用程式的選擇器上使用了 *ngIf。這將不會初始化 hello 元件,直到 app.component.ts 中的 name 變數有值為止。所以當你第一次點擊 emit 時,name 變數會先被賦值,然後你的 hello 元件才會初始化。接著在第二次點擊後,hello 應用程式中的 name 變數將被賦值為 "world",然後它就會被顯示出來。

解答如下。

<hello>
  <label *ngIf="name">
    {{name}}
  </label>
</hello>
<show></show>