angular2-组件

@Input 数据从父组件传到子组件

子组件:

import { Component, Input } from '@angular/core';
import { Hero } from './hero';
 
@Component({
  selector: 'app-hero-child',
  template: `
    <h3>{{hero.name}} //使用// says:</h3>
    <p>I, {{hero.name}}, am at your service, {{masterName}}.</p>
  `
})
export class HeroChildComponent {
  @Input() hero: Hero;
  @Input('master') masterName: string;
}

第二个@Input为子组件的属性名masterName指定一个别名master(译者注:不推荐为起别名,请参见风格指南)

 

父组件:

import { Component } from '@angular/core';
import { HEROES } from './hero';
 
@Component({
  selector: 'app-hero-parent',
  template: `
    <h2>{{master}} controls {{heroes.length}} heroes</h2>
    <app-hero-child *ngFor="let hero of heroes"
      [hero]="hero" // 子组件的 @Input() hero: Hero 对应这里的 [hero]
      [master]="master" // @Input('master') masterName 对应这里的 【master】
>
</app-hero-child> ` }) export class HeroParentComponent { heroes = HEROES; master = 'Master'; }

  

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

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

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

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

  

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

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

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

 

 

父组件监听子组件的事件(EventEmitter)

子组件暴露一个EventEmitter属性,当事件发生时,子组件利用该属性emits(向上弹射)事件。父组件绑定到这个事件属性,并在事件发生时作出回应。

子组件的EventEmitter属性是一个输出属性,通常带有@Output装饰器,就像在VoterComponent中看到的

子组件:

import { Component, EventEmitter, Input, Output } from '@angular/core';
 
@Component({
  selector: 'app-voter',
  template: `
    <h4>{{name}}</h4>
    <button (click)="vote(true)"  [disabled]="voted">Agree</button>
    <button (click)="vote(false)" [disabled]="voted">Disagree</button>
  `
})
export class VoterComponent {
  @Input()  name: string;
  @Output() onVoted = new EventEmitter<boolean>();
  voted = false;
 
  vote(agreed: boolean) {
    this.onVoted.emit(agreed);
    this.voted = true;
  }
}

  

父组件:

import { Component }      from '@angular/core';
 
@Component({
  selector: 'app-vote-taker',
  template: `
    <app-voter *ngFor="let voter of voters"
      [name]="voter"
    // onVoted 对应 子组件的@Output onVoted (onVoted)="onVoted($event)"> </app-voter> ` }) export class VoteTakerComponent { onVoted(agreed: boolean) { // agreed 就是子组件传递的参数 } }

  

子组件:点击按钮会触发truefalse(布尔型有效载荷)的事件。

父组件:VoteTakerComponent绑定了一个事件处理器(onVoted()),用来响应子组件的事件($event)并更新一个计数器。

 

父组件调用子组件方法或者属性

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

  • 父组件模板上调用子组件的方法:

子组件:

  start() { 
  }
  stop()  {
  }

父组件:

  template: `
  <button (click)="timer.start()">Start</button>
  <button (click)="timer.stop()">Stop</button>
  <app-countdown-timer #timer></app-countdown-timer>
  `,

 

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

 

  • 父组件js 调用子组件的方法@ViemChild():

父组件:

import { AfterViewInit, ViewChild } from '@angular/core';
import { Component }                from '@angular/core';
import { CountdownTimerComponent }  from './countdown-timer.component';
 
@Component({
  selector: 'app-countdown-parent-vc',
  template: `
  <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 {
 
  @ViewChild(CountdownTimerComponent)
  private timerComponent: CountdownTimerComponent;
 
  seconds() { return 0; }
 
  ngAfterViewInit() {
    setTimeout(() => this.seconds = () => this.timerComponent.seconds, 0);
  }
 
  start() { this.timerComponent.start(); }
  stop() { this.timerComponent.stop(); }
}

  

通过@ViewChild属性装饰器,将子组件CountdownTimerComponent注入到私有属性timerComponent里面

组件元数据里就不再需要#timer本地变量了。而是把按钮绑定到父组件自己的startstop方法

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

(子组件CountdownTimerComponent和原来一样)

 

 

 

父组件和子组件通过服务来通讯???

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

该服务实例的作用域被限制在父组件和其子组件内。这个组件子树之外的组件将无法访问该服务或者与它们通讯。

这个MissionServiceMissionControlComponent和多个AstronautComponent子组件连接起来

 

import { Injectable } from '@angular/core';
import { Subject }    from 'rxjs/Subject';
 
@Injectable()
export class MissionService {
 
  // Observable string sources
  private missionAnnouncedSource = new Subject<string>();
  private missionConfirmedSource = new Subject<string>();
 
  // Observable string streams
  missionAnnounced$ = this.missionAnnouncedSource.asObservable();
  missionConfirmed$ = this.missionConfirmedSource.asObservable();
 
  // Service message commands
  announceMission(mission: string) {
    this.missionAnnouncedSource.next(mission);
  }
 
  confirmMission(astronaut: string) {
    this.missionConfirmedSource.next(astronaut);
  }
}

  

MissionControlComponent提供服务的实例,并将其共享给它的子组件(通过providers元数据数组),子组件可以通过构造函数将该实例注入到自身

 

父组件:MissionControlComponent

import { Component }          from '@angular/core';
import { MissionService }     from './mission.service';
 
@Component({
  selector: 'app-mission-control',
  template: `
    <button (click)="announce()">Announce mission</button>
    <app-astronaut *ngFor="let astronaut of astronauts"
      [astronaut]="astronaut">
    </app-astronaut>
    <h3>History</h3>
    <ul>
      <li *ngFor="let event of history">{{event}}</li>
    </ul>
  `,
  providers: [MissionService]
})
export class MissionControlComponent {
  astronauts = ['Lovell', 'Swigert', 'Haise'];
  history: string[] = [];
  missions = ['Fly to the moon!',
              'Fly to mars!',
              'Fly to Vegas!'];
  nextMission = 0;
 
  constructor(private missionService: MissionService) {
    missionService.missionConfirmed$.subscribe(
      astronaut => {
        this.history.push(`${astronaut} confirmed the mission`);
      });
  }
 
  announce() {
    let mission = this.missions[this.nextMission++];
    this.missionService.announceMission(mission);
    this.history.push(`Mission "${mission}" announced`);
    if (this.nextMission >= this.missions.length) { this.nextMission = 0; }
  }
}

  

子组件:AstronautComponent

AstronautComponent也通过自己的构造函数注入该服务。由于每个AstronautComponent都是MissionControlComponent的子组件,所以它们获取到的也是父组件的这个服务实例

mport { Component, Input, OnDestroy } from '@angular/core';
import { MissionService } from './mission.service';
import { Subscription }   from 'rxjs/Subscription';
 
@Component({
  selector: 'app-astronaut',
  template: `
    <p>
      {{astronaut}}: <strong>{{mission}}</strong>
      <button
        (click)="confirm()"
        [disabled]="!announced || confirmed">
        Confirm
      </button>
    </p>
  `
})
export class AstronautComponent implements OnDestroy {
  @Input() astronaut: string;
  mission = '<no mission announced>';
  confirmed = false;
  announced = false;
  subscription: Subscription;
 
  constructor(private missionService: MissionService) {
    this.subscription = missionService.missionAnnounced$.subscribe(
      mission => {
        this.mission = mission;
        this.announced = true;
        this.confirmed = false;
    });
  }
 
  confirm() {
    this.confirmed = true;
    this.missionService.confirmMission(this.astronaut);
  }
 
  ngOnDestroy() {
    // prevent memory leak when component destroyed
    this.subscription.unsubscribe();
  }
}

  

 

转载于:https://www.cnblogs.com/vs1435/p/7792433.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值