Angular笔记(三)组件交互

文章目录

    • 一、Input
    • 二、Input:setter
    • 三、ngOnChanges() 监测
    • 四、Output
    • 五、本地变量#表示组件
    • 六、父级调用 @ViewChild()
    • 七、服务 service

一、Input

子:

@Input() hero!: Hero;
@Input('master') masterName = ''; //不推荐起别名

父:

//html:
<app-hero-child [hero]="hero" [master]="master"> </app-hero-child>
//ts:
export class HeroParentComponent {
  hero = '';
  master = 'Master';
}

二、Input:setter

使用一个输入属性的 setter,以拦截父组件中值的变化,并采取行动。

e.g. 子组件 NameChildComponent 的输入属性 name 上的这个 setter,会 trim 掉名字里的空格,并把空值替换成默认字符串。

子:

export class NameChildComponent {
  @Input()
  get name(): string { return this._name; }
  set name(name: string) {
    this._name = (name && name.trim()) || '';
  }
  private _name = '';
}

父:

//html
<app-name-child *ngFor="let name of names" [name]="name"></app-name-child>
//ts
export class NameParentComponent {
  // Displays 'Dr. IQ', '', 'Bombasto'
  names = ['Dr. IQ', '   ', '  Bombasto  '];
}

三、ngOnChanges() 监测

使用 OnChanges 生命周期钩子接口的 ngOnChanges() 方法来监测输入属性值的变化并做出回应。

当需要监视多个、交互式输入属性的时候,本方法比用属性的 setter 更合适。

四、Output

子组件暴露一个 EventEmitter 属性,当事件发生时,子组件利用该属性 emits(向上弹射)事件。
父组件绑定到这个事件属性,并在事件发生时作出回应。
【 子组件的 EventEmitter 属性是一个输出属性,通常带有**@Output** 装饰器 】

本框架把事件参数(用 $event 表示)传给事件处理方法

子:

//html
<button type="button" (click)="vote(true)">Agree</button>
//ts
@Output() voted = new EventEmitter<boolean>();
vote(agreed: boolean) {
    this.voted.emit(agreed);
}

父:

//html
<app-voter [name]="voter" (voted)="onVoted($event)"></app-voter>
//ts
onVoted(agreed: boolean) { //Todo }

五、本地变量#表示组件

父组件不能使用数据绑定来读取子组件的属性或调用子组件的方法。但可以在父组件模板里,新建一个本地变量来代表子组件,然后利用这个变量来读取子组件的属性和调用子组件的方法。

子:

//ts
start() { this.countDown(); }
stop()  {this.clearTimer(); }

父:

//html
<button type="button" (click)="timer.start()">Start</button>
<button type="button" (click)="timer.stop()">Stop</button>
<div class="seconds">{{timer.seconds}}</div>
<app-countdown-timer #timer></app-countdown-timer>

Q:父组件不能通过数据绑定使用子组件的 start 和 stop 方法,也不能访问子组件的 seconds 属性。

A:把本地变量(#timer)放到()标签中,用来代表子组件。
这样父组件的模板就得到了子组件的引用,于是可以在父组件的模板中访问子组件的所有属性和方法。

六、父级调用 @ViewChild()

这个本地变量方法是个简单明了的方法。
局限性:父组件本身的代码对子组件没有访问权【父组件-子组件的连接全部在父组件的模板中进行】
=> 如果父组件的类需要依赖于子组件类,就不能使用本地变量方法。

父:

//html
<button type="button" (click)="start()">Start</button>
<button type="button" (click)="stop()">Stop</button>
<div class="seconds">{{ seconds() }}</div>
<app-countdown-timer></app-countdown-timer>

//ts
export class CountdownViewChildParentComponent implements AfterViewInit {

  @ViewChild(CountdownTimerComponent)
  private timerComponent!: CountdownTimerComponent; //子组件

  seconds() { return 0; }

  ngAfterViewInit() {
    // Redefine `seconds()` to get from the `CountdownTimerComponent.seconds` ...
    // but wait a tick first to avoid one-time devMode
    // unidirectional-data-flow-violation error
    setTimeout(() => this.seconds = () => this.timerComponent.seconds, 0);
  }

  start() { this.timerComponent.start(); }
  stop() { this.timerComponent.stop(); }
}
  1. 必须导入对装饰器 ViewChild 以及生命周期钩子 AfterViewInit 的引用
  2. 通过 @ViewChild 属性装饰器,将子组件 CountdownTimerComponent 注入到私有属性 timerComponent 里面
  3. 把按钮绑定到父组件自己的 start 和 stop 方法,使用父组件的 seconds 方法的插值

ngAfterViewInit() 生命周期钩子是非常重要的一步。
被注入的计时器组件只有在 Angular 显示了父组件视图之后才能访问,所以它先把秒数显示为 0。

七、服务 service

父组件和它的子组件共享同一个服务,利用该服务在组件家族内部实现双向通讯

你可能感兴趣的:(Angular,angular.js,javascript,前端)