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


Posted in Javascript onJanuary 29, 2018

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

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

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

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

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

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

通过@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、)点击按钮触发发射事件,将数据传送给父组件。)

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

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

效果如下:

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

父组件核心代码:

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

效果如下:

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

父子组件的核心代码类似,在构造函数中将该服务实例注入到自身,父子组件都有一个唯一的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周期中,要取消订阅。

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

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

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

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

Javascript 相关文章推荐
JQuery 无废话系列教程(一) jquery入门 [推荐]
Jun 23 Javascript
js 中 document.createEvent的用法
Aug 29 Javascript
Fixie.js 自动填充内容的插件
Jun 28 Javascript
js格式化金额可选是否带千分位以及保留精度
Jan 28 Javascript
多个checkbox被选中时如何判断是否有自己想要的
Sep 22 Javascript
自定义jQuery插件方式实现强制对象重绘的方法
Mar 23 Javascript
jQuery的end()方法使用详解
Jul 15 Javascript
理解JS事件循环
Jan 07 Javascript
jQuery实现验证年龄简单思路
Feb 24 Javascript
理解js回收机制通俗易懂版
Feb 29 Javascript
JavaScript中在光标处插入添加文本标签节点的详细方法
Mar 22 Javascript
解决vue语法会有延迟加载显现{{xxx}}的问题
Nov 14 Javascript
jQuery代码优化方法总结
Jan 29 #jQuery
javascript代码优化的8点总结
Jan 29 #Javascript
浅析Node.js非对称加密方法
Jan 29 #Javascript
360doc网站不登录就无法复制内容的解决方法
Jan 27 #Javascript
使用Vue写一个datepicker的示例
Jan 27 #Javascript
Vue引用第三方datepicker插件无法监听datepicker输入框的值的解决
Jan 27 #Javascript
浅谈React中组件间抽象
Jan 27 #Javascript
You might like
php jquery 实现新闻标签分类与无刷新分页
2009/12/18 PHP
ThinkPHP实现动态包含文件的方法
2014/11/29 PHP
IE事件对象(The Internet Explorer Event Object)
2012/06/27 Javascript
用jquery生成二级菜单的实例代码
2013/06/24 Javascript
Javascript高级技巧分享
2014/02/25 Javascript
JavaScript String 对象常用方法详解
2016/05/13 Javascript
轻松搞定js表单验证
2016/10/13 Javascript
理解javascript async的用法
2017/08/22 Javascript
node 使用 async 控制并发的方法
2018/05/07 Javascript
Vue开发实现吸顶效果的示例代码
2018/08/21 Javascript
详解微信UnionID作用
2019/05/15 Javascript
Javascript confirm多种使用方法解析
2020/09/25 Javascript
[00:58]他们到底在电话里听到了什么?
2017/11/21 DOTA
在Python中使用lambda高效操作列表的教程
2015/04/24 Python
调试Python程序代码的几种方法总结
2015/04/28 Python
Python中的Descriptor描述符学习教程
2016/06/02 Python
python删除某个字符
2018/03/19 Python
Python实现的建造者模式示例
2018/08/06 Python
python安装twisted的问题解析
2018/08/21 Python
centos7之Python3.74安装教程
2019/08/15 Python
Django如何批量创建Model
2020/09/01 Python
python实现猜拳游戏项目
2020/11/30 Python
新秀丽拉杆箱美国官方网站:Samsonite美国
2016/07/25 全球购物
布鲁明戴尔百货店:Bloomingdale’s
2016/12/21 全球购物
德国家具在线:Fashion For Home
2017/03/11 全球购物
经典c++面试题三
2015/07/08 面试题
既然说Ruby中一切都是对象,那么Ruby中类也是对象吗
2013/01/26 面试题
青年文明号事迹材料
2014/01/18 职场文书
学生感冒英文请假条
2014/02/04 职场文书
运动会演讲稿50字
2014/08/25 职场文书
2014年重阳节老干部座谈会局领导发言稿
2014/09/25 职场文书
班主任经验交流材料
2014/12/16 职场文书
《狼牙山五壮士》教学反思
2016/02/17 职场文书
2016年党员干部廉政承诺书
2016/03/24 职场文书
导游词创作书写原则以及开场白技巧怎么学?
2019/09/25 职场文书
详解Java实践之抽象工厂模式
2021/06/18 Java/Android