angular 2+ 点点滴滴让前端飞Web前端之路

Angular2 父子组件通信方式

2018-01-28  本文已影响150人  Husbin
  1. 通过输入型绑定把数据从父组件传到子组件(@Input decoration);子组件暴露一个EventEmitter属性(@Output decoration),当事件发生时,利用该属性emits向父组件发射事件。
  2. 父组件与子组件通过本地变量互动。(# var
  3. 父组件调用@ViewChild
  4. 父组件和子组件通过服务来通讯。
image.png image.png

通过@Input@Output装饰器进行父、子组件间的通信

<!--parent.component.html-->
<div style="width: 1000px;margin: auto">
<div class="card" style="width: 500px;float: left">
  <div class="card-header">
    父组件
  </div>
  <div class="card-body">
    <h5 class="card-title">父组件</h5>
    <div class="form-group">
      <label for="input">父组件输入:</label>
      <input type="text"
             class="form-control"
             id="input"
             placeholder="Input something"
             [(ngModel)]="parentPrint"  
      >
      <label for="output">父组件输出:</label>
      <input type="text"
             class="form-control"
             id="output"
             placeholder="Output something"
             [(ngModel)]="contentFromChild"
      >
    </div>
  </div>
</div>
<app-child
  [fromParent]="parentPrint"
  (fromChild)="fromChild($event)"
></app-child>
</div>

<!--child.component.html-->
<div class="card" style="width: 500px;">
  <div class="card-header">
    子组件
  </div>
  <div class="card-body">
    <h5 class="card-title">子组件</h5>
    <div class="form-group">
      <label for="input">子组件输入:</label>
      <input type="text"
             class="form-control"
             id="input"
             placeholder="Input something"
             [(ngModel)]="contentFromChild"
      >
      <label for="output">子组件输出:</label>
      <input type="text"
             class="form-control"
             id="output"
             placeholder="Output something"
             [(ngModel)]="fromParent"
      >
    </div>
    <button  class="btn btn-primary" (click)="clickChild()">Output方式</button>
  </div>
</div>
image.png
//父组件
parentPrint: any;           //ts中,声明一个变量
[(ngModel)]="parentPrint"   //html中,绑定变量,获取用户输入
//html中,将数据传给子组件
<app-child [fromParent]="parentPrint"></app-child> 
//子组件
@Input() fromParent;        //ts中,用于直接接收从父组件获取的数据
[(ngModel)]="fromParent"    //html中,用于显示数据
//子组件
 private _fromParent: any;      //私有变量,通过setter获取父组件的数据
@Input()                        //通过setter获取父组件的数据
  set fromParent(fromParent: any) {
    this._fromParent = fromParent;
  }
  get fromParent(): any {
    return this._fromParent;
  }
//子组件
@Output() fromChild = new EventEmitter<any>();  //暴露一个输出属性

<button  class="btn btn-primary" (click)="clickChild()">Output方式</button> 
 //触发发射函数,将数据发送给父组件
  clickChild() {
    console.log('click child' , this.contentFromChild);
    this.fromChild.emit(this.contentFromChild);
  }

//父组件
[(ngModel)]="contentFromChild"  //绑定输出子组件的数据
//使用子组件,绑定事件属性
<app-child
  [fromParent]="parentPrint"
  (fromChild)="fromChild($event)"
></app-child>
//事件处理函数
 fromChild(event) {
   console.log(event);
   this.contentFromChild = event;
 }

父组件通过调用@ViewChild()来获取子组件的数据

<!--parent.component.html-->
<div style="width: 1000px;margin: auto">
<div class="card" style="width: 500px;float: left">
  <div class="card-header">
    父组件
  </div>
  <div class="card-body">
    <h5 class="card-title">父组件</h5>
    <div class="form-group">
      <label for="viewoutput">ViewChild父组件输出:</label>
      <input type="text"
             class="form-control"
             id="viewoutput"
             placeholder="ViewChild父组件输出"
             [(ngModel)]="viewOutput"
      >
    </div>
    <button class="btn btn-primary" (click)="clickView()">ViewChild方式</button>
  </div>
</div>
<app-child></app-child>
</div>
<!--child.component.html-->
<div class="card" style="width: 500px;">
  <div class="card-header">
    子组件
  </div>
  <div class="card-body">
    <h5 class="card-title">子组件</h5>
    <div class="form-group">
      <label for="input">子组件输入:</label>
      <input type="text"
             class="form-control"
             id="input"
             placeholder="Input something"
             [(ngModel)]="contentFromChild"
      >
    </div>
  </div>
</div>

image.png
//ts
@ViewChild(ChildComponent)                  // 使用viewChild导入引用
private childComponent: ChildComponent;     // 将子组件注入到私有属性
//获取子组件数据并显示
clickView() {
    //直接获取子组件的属性
    this.viewOutput = this.childComponent.contentFromChild;
  }

//html
[(ngModel)]="viewOutput"
 <button class="btn btn-primary" (click)="clickView()">ViewChild方式</button>

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

<!--parent.component.html-->
<div style="width: 1000px;margin: auto">
<div class="card" style="width: 500px;float: left">
  <div class="card-header">
    父组件
  </div>
  <div class="card-body">
    <h5 class="card-title">父组件</h5>
    <div class="form-group">
      <label for="serviceoutput">父组件服务输入:</label>
      <input type="text"
             class="form-control"
             id="serviceoutput"
             placeholder="服务输入"
             [(ngModel)]="serviceInput"
      >
    </div>
    <button class="btn btn-primary" (click)="clickService()">Service方式</button>
  </div>
</div>
<app-child></app-child>
</div>

<!--child.component.html-->
<div class="card" style="width: 500px;">
  <div class="card-header">
    子组件
  </div>
  <div class="card-body">
    <h5 class="card-title">子组件</h5>
    <div class="form-group">
      <label for="serviceoutput">子组件服务输入:</label>
      <input type="text"
             class="form-control"
             id="serviceoutput"
             placeholder="服务输入"
             [(ngModel)]="serviceInput"
      >
    </div>
    <button class="btn btn-primary" (click)="clickService()">Service方式</button>
  </div>
</div>

//服务
//meditor.service.ts
import {Injectable} from '@angular/core';
import {Subject} from 'rxjs/Subject';
import {Observable} from 'rxjs/Observable';

@Injectable()
export class MeditorService {
  private subject = new Subject<MeditorMsg>();
  constructor() {}
  // 获取订阅者
  public getObservable(): Observable<MeditorMsg> {
    return this.subject.asObservable();
  }
  // 推送信息
  public push(msg: MeditorMsg) {
    this.subject.next(msg);
  }
}
// 中间者信息
export interface MeditorMsg {
  id: string;
  body: any;
}
image.png

subscription: Subscription = null;  //初始化一个订阅对象
//子组件构造函数,用于监听数据推送
constructor(
    private meditor: MeditorService
  ) {
    this.subscription = meditor.getObservable().subscribe(
      msg => {
        console.log(msg);
        if (msg.id === 'parent') {      //id为parent,获取父组件数据
          this.serviceInput = msg.body;
        }
      }
    );
  }
// 子组件将数据推送到中间着,给订阅者
clickService() {
    this.meditor.push({id: 'parent', body: this.serviceInput});
  }
//父组件构造函数,用于监听数据推送
constructor(
    private meditor: MeditorService
  ) {
    this.subscription = meditor.getObservable().subscribe(
      msg => {
        console.log(msg);
        if (msg.id === 'child') {       //id为child,获取子组件数据
          this.serviceInput = msg.body;
        }
      }
    );
  }
// 父组件将数据推送到中间着,给订阅者
clickService() {
    this.meditor.push({id: 'parent', body: this.serviceInput});
  }

​ 以上,就是最近在使用的组件交互的总结。个人觉得通过服务来交互的可扩展性更强。例如,我们项目中用到了一个动态显示的侧栏,不同时期点击显示侧栏要显示不同的东西。这个时候把侧栏作为父组件,子组件作为消息的一部分传递给父组件,父组件根据子组件名动态生成模板,显示在侧栏上面。说了这么多废话大概就是下图的意思:

image.png

最后附上demo源码:父子组件交互demo

上一篇 下一篇

猜你喜欢

热点阅读