Angular2 父子组件通信方式的示例

 更新时间:2018年01月29日 10:07:30   作者:Husbin  
本篇文章主要介绍了Angular2 父子组件通信方式的示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

Angular2官方文档对组件交互这块有详细的介绍-->文档--组件之间的交互。按文档介绍,组件间交互的方式一共有4种,包括:

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

我在这里只总结、详细介绍3种我在项目中使用过的方法,看完本文大概能做到如下的效果:


创建项目,项目结构如下:


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

@Input:该属性绑定用于父组件向子组件传递数据。子组件可以通过以下两种方法截取属性的变更:

  1. 使用一个输入属性的setter,以拦截父组件中值得变化。
  2. 通过ngOnchanges()来截听输入属性值的变化。

@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>

效果如下:(1、父组件输入,子组件可同步输出;2、子组件输入需要(3、)点击按钮触发发射事件,将数据传送给父组件。)


@Input:父组件输入的同时,子组件能同步获取数据进行显示。核心代码如下:

//父组件
parentPrint: any;      //ts中,声明一个变量
[(ngModel)]="parentPrint"  //html中,绑定变量,获取用户输入
//html中,将数据传给子组件
<app-child [fromParent]="parentPrint"></app-child> 
//子组件
@Input() fromParent;    //ts中,用于直接接收从父组件获取的数据
[(ngModel)]="fromParent"  //html中,用于显示数据

通过setter截听输入属性值的变化,在子组件中声明一个私有变量来获取父组件传递过来的数据,从而屏蔽上层获取下层信息。(简单一点就是不让父组件知道子组件用什么东西去接收传过来的数据)通过这种方法也可以获得同样的效果。

//子组件
 private _fromParent: any;   //私有变量,通过setter获取父组件的数据
@Input()            //通过setter获取父组件的数据
 set fromParent(fromParent: any) {
  this._fromParent = fromParent;
 }
 get fromParent(): any {
  return this._fromParent;
 }

@Output:父组件接收子组件的数据时,子组件暴露一个EventEmitter属性,当事件发生时,子组件利用该属性emits(向上弹射)事件。父组件绑定到这个事件属性,并在事件发生时作出回应。核心代码如下:

//子组件
@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()来获取子组件的数据

如果父组件的类需要读取子组件的属性和值或调用子组件的方法时,就可以把子组件作为ViewChild,注入到父组件里面。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>

效果如下:

父组件核心代码:

//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;
}

效果如下:


父子组件的核心代码类似,在构造函数中将该服务实例注入到自身,父子组件都有一个唯一的id。无论是父组件还是子组件调用push()方法推送数据,双方都能接收到数据,这时候就要根据id来判断是要父组件使用数据还是子组件使用数据。核心代码如下:

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});
 }

我上面写的还不是很完善,就是在生命周期结束前,也就是在onDestroy周期中,要取消订阅。

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


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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • Angular5整合富文本编辑器TinyMCE的方法(汉化+上传)

    Angular5整合富文本编辑器TinyMCE的方法(汉化+上传)

    TinyMCE是一个轻量级的富文本编辑器,相对于CK编辑器更加精简,但必须满足绝大部分场景的需要。这篇文章主要介绍了Angular5整合富文本编辑器TinyMCE(汉化+上传)的相关知识,需要的朋友可以参考下
    2020-05-05
  • Angular实现预加载延迟模块的示例

    Angular实现预加载延迟模块的示例

    本篇文章主要介绍了Angular实现预加载延迟模块的示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-10-10
  • angularjs 实现带查找筛选功能的select下拉框实例

    angularjs 实现带查找筛选功能的select下拉框实例

    本篇文章主要介绍了angularjs 实现带查找筛选功能的select下拉框实例,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
    2017-01-01
  • angularjs 源码解析之scope

    angularjs 源码解析之scope

    $scope 的使用贯穿整个 Angular App 应用,它与数据模型相关联,同时也是表达式执行的上下文.有了 $scope 就在视图和控制器之间建立了一个通道,基于作用域视图在修改数据时会立刻更新 $scope,同样的 $scope 发生改变时也会立刻重新渲染视图.
    2016-08-08
  • Angular1.x自定义指令实例详解

    Angular1.x自定义指令实例详解

    这篇文章主要介绍了Angular1.x自定义指令,结合实例形式分析了Angular1.x自定义指令的实现与使用方法,以及相关操作技巧与注意事项,需要的朋友可以参考下
    2017-03-03
  • 详解AngularJS中的作用域

    详解AngularJS中的作用域

    这篇文章主要介绍了详解AngularJS中的作用域,是AngularJS学习中的基础知识,需要的朋友可以参考下
    2015-06-06
  • angular.js和vue.js中实现函数去抖示例(debounce)

    angular.js和vue.js中实现函数去抖示例(debounce)

    这篇文章主要介绍了angular.js和vue.js中实现函数去抖示例(debounce),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-01-01
  • 关于Angularjs中自定义指令一些有价值的细节和技巧小结

    关于Angularjs中自定义指令一些有价值的细节和技巧小结

    这篇文章主要介绍了关于Angularjs中自定义指令一些有价值的细节和技巧小结,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-04-04
  • 基于Angularjs实现分页功能

    基于Angularjs实现分页功能

    这篇文章主要介绍了基于Angularjs实现分页功能的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2016-05-05
  • AngularJS 获取ng-repeat动态生成的ng-model值实例详解

    AngularJS 获取ng-repeat动态生成的ng-model值实例详解

    这篇文章主要介绍了AngularJS 获取ng-repeat动态生成的ng-model值实例详解的相关资料,这里提供实例代码及实现效果图,需要的朋友可以参考下
    2016-11-11

最新评论