父 -> 子

通过输入型把数据从父组件传到子组件

父组件

    <app-hero-child *ngFor="let hero of heroes"
      [hero]="hero"
      [master]="master">
    </app-hero-child>

子组件

export class HeroChildComponent {
  @Input() hero: Hero;
  @Input('master') masterName: string;
}

给master属性起了一个别名masterName

通过setter截听输入属性值的变化

父组件

<app-name-child *ngFor="let name of names" [name]="name"></app-name-child>

子组件

export class NameChildComponent {
  private _name = '';

  @Input()
  set name(name: string) {
    this._name = (name && name.trim()) || '<no name set>';
  }

  get name(): string { return this._name; }
}

通过ngOnChanges()来截听输入属性值得变化

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

父组件

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

@Component({
  selector: 'app-version-parent',
  template: `
    <h2>Source code version</h2>
    <button (click)="newMinor()">New minor version</button>
    <button (click)="newMajor()">New major version</button>
    <app-version-child [major]="major" [minor]="minor"></app-version-child>
  `
})
export class VersionParentComponent {
  major = 1;
  minor = 23;

  newMinor() {
    this.minor++;
  }

  newMajor() {
    this.major++;
    this.minor = 0;
  }
}

子组件

export class VersionChildComponent implements OnChanges {
  @Input() major: number;
  @Input() minor: number;
  changeLog: string[] = [];

  ngOnChanges(changes: {[propKey: string]: SimpleChange}) {
    let log: string[] = [];
    for (let propName in changes) {
      let changedProp = changes[propName];
      let to = JSON.stringify(changedProp.currentValue);
      if (changedProp.isFirstChange()) {
        log.push(`Initial value of ${propName} set to ${to}`);
      } else {
        let from = JSON.stringify(changedProp.previousValue);
        log.push(`${propName} changed from ${from} to ${to}`);
      }
    }
    this.changeLog.push(log.join(', '));
  }
}

子 -> 父

父组件监听子组件的事件

子组件

export class VoterComponent {
  @Input()  name: string;
  @Output() voted = new EventEmitter<boolean>();//==>1 声明EventEmitter
  didVote = false;

  vote(agreed: boolean) {
    this.voted.emit(agreed); //==>2 向外发射事件
    this.didVote = true;
  }
}

父组件

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

@Component({
  selector: 'app-vote-taker',
  template: `
    <h2>Should mankind colonize the Universe?</h2>
    <h3>Agree: {{agreed}}, Disagree: {{disagreed}}</h3>
    <app-voter *ngFor="let voter of voters"
      [name]="voter"
      (voted)="onVoted($event)"> //1==>父组件使用onVoted($event)进行接收
    </app-voter>
  `
})
export class VoteTakerComponent {
  agreed = 0;
  disagreed = 0;
  voters = ['Mr. IQ', 'Ms. Universe', 'Bombasto'];
  //2==>定义接收函数以及参数
  onVoted(agreed: boolean) {
    agreed ? this.agreed++ : this.disagreed++;
  }
}

父组件与子组件通过“本地变量”互动

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

子组件

import { Component, OnDestroy, OnInit } from '@angular/core';

@Component({
  selector: 'app-countdown-timer',
  template: '<p>{{message}}</p>'
})
export class CountdownTimerComponent implements OnInit, OnDestroy {

  intervalId = 0;
  message = '';
  seconds = 11;

  clearTimer() { clearInterval(this.intervalId); }

  ngOnInit()    { this.start(); }
  ngOnDestroy() { this.clearTimer(); }

  start() { this.countDown(); }
  stop()  {
    this.clearTimer();
    this.message = `Holding at T-${this.seconds} seconds`;
  }

  private countDown() {
    this.clearTimer();
    this.intervalId = window.setInterval(() => {
      this.seconds -= 1;
      if (this.seconds === 0) {
        this.message = 'Blast off!';
      } else {
        if (this.seconds < 0) { this.seconds = 10; } // reset
        this.message = `T-${this.seconds} seconds and counting`;
      }
    }, 1000);
  }
}

父组件

import { Component }                from '@angular/core';
import { CountdownTimerComponent }  from './countdown-timer.component';

@Component({
  selector: 'app-countdown-parent-lv',
  template: `
  <h3>Countdown to Liftoff (via local variable)</h3>
  <button (click)="timer.start()">Start</button>//2==>引用子组件方法
  <button (click)="timer.stop()">Stop</button>//3==>引用子组件方法
  <div class="seconds">{{timer.seconds}}</div>//4==>引用子组件变量
  <app-countdown-timer #timer></app-countdown-timer>//1==>定义变量
  `,
  styleUrls: ['../assets/demo.css']
})
export class CountdownLocalVarParentComponent { }

父组件调用@ViewChild()

“本地变量”方法是个简单便利的方法。但是它有局限性。因为父组件-子组件的连接必须全部在父组件的模板中进行。父组件本身的代码对子组件没有访问权

如果父组件的类需要读取子组件的属性值或调用子组件的方法,就不能使用“本地变量”方法

当父组件类需要这种访问时,可以把子组件作为ViewChild,注入到父组件里面

子组件代码同上面一样

父组件代码

import { AfterViewInit, ViewChild } from '@angular/core';//1==>引入对象
import { Component }                from '@angular/core';
import { CountdownTimerComponent }  from './countdown-timer.component';

@Component({
  selector: 'app-countdown-parent-vc',
  template: `
  <h3>Countdown to Liftoff (via ViewChild)</h3>
  <button (click)="start()">Start</button>
  <button (click)="stop()">Stop</button>
  <div class="seconds">{{ seconds() }}</div>
  <app-countdown-timer></app-countdown-timer>
  `,
  styleUrls: ['../assets/demo.css']
})
export class CountdownViewChildParentComponent implements AfterViewInit {//2==>挂上AfterViewInit生命周期的钩子

  @ViewChild(CountdownTimerComponent)//2==>把子组件注入到父组件中
  private timerComponent: CountdownTimerComponent;//3==>定义相应的变量接收

  seconds() { return 0; }

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

    然后 Angular 会调用 ngAfterViewInit 生命周期钩子,但这时候再更新父组件视图的倒计时就已经太晚了。Angular 的单向数据流规则会阻止在同一个周期内更新父组件视图。应用在显示秒数之前会被迫再等一轮。

    使用 setTimeout() 来等下一轮,然后改写 seconds() 方法,这样它接下来就会从注入的这个计时器组件里获取秒数的值。
    setTimeout(() => this.seconds = () => this.timerComponent.seconds, 0);
  }

  start() { this.timerComponent.start(); }//4==>直接调用子组件的方法
  stop() { this.timerComponent.stop(); }
}

父组件和子组件通过服务来通讯(rxjs)

引用message组件的代码

message.service.ts

import { Injectable } from "@angular/core";
import { Subject } from "rxjs";
import { IType } from "./IMessage";
@Injectable({
  providedIn: "root"
})
export class MessageService {
  private messages = new Subject<string>();
  messages$ = this.messages.asObservable();
  constructor() {}
  // 主要是负责对外提供接口方法,当外部调用时,传入了相应值,子组件只需要监听该流即可
  success(content: string) {
    this.next(content, IType.success);
  }
  info(content: string) {
    this.next(content, IType.info);
  }
  error(content: string) {
    this.next(content, IType.error);
  }
  private next(content: string, type: IType) {
    this.messages.next(
      JSON.stringify({
        content,
        type
      })
    );
  }
}

message-container.component.ts

import { Component, OnDestroy, OnInit } from "@angular/core";
import { IMessage, IType } from "../IMessage";
import { MessageService } from "../message.service";
import { Subscription } from "rxjs";

@Component({
  selector: "message-container",
  templateUrl: "./message-container.component.html",
  styleUrls: ["./message-container.component.scss"]
})
export class MessageContainerComponent implements OnInit, OnDestroy {
  messages: IMessage[] = [];
  constructor(private messageService: MessageService) {}
  subscription: Subscription;
  ngOnInit() {
    //1==> 子组件进行监听流的数据,当有数据推送到流中,即往数组中推送增加一条信息,并展示到界面中,这样就实现了,通过service服务来通讯
    this.subscription = this.messageService.messages$.subscribe(val => {
      this.create(content, type);
    });
  }
  ngOnDestroy() {
    this.subscription.unsubscribe();//退订订阅非常重要,防止内存泄露
  }
  create(content: string, type: IType) {
  }
  removeMessage(messageId: number) {
  }
  _generateMessageId() {
  }
}
Copyright © frankshi.com 2019 all right reserved,powered by Gitbook该文件修订时间: 2019-06-04 07:42:19

results matching ""

    No results matching ""