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 相关文章推荐
怎么用javascript进行拖拽
Jul 20 Javascript
iis6+javascript Add an Extension File
Jun 13 Javascript
jQuery实现原理的模拟代码 -6 代码下载
Aug 16 Javascript
js/ajax跨越访问-jsonp的原理和实例(javascript和jquery实现代码)
Dec 27 Javascript
js实现点击后将文字或图片复制到剪贴板的方法
Aug 04 Javascript
浅谈javascript构造函数与实例化对象
Jun 22 Javascript
JQuery中Ajax的操作完整例子
Mar 07 Javascript
还不懂递归?读完这篇文章保证你会懂
Jul 29 Javascript
详解vscode中vue代码颜色插件
Oct 11 Javascript
VUE2.0+ElementUI2.0表格el-table实现表头扩展el-tooltip
Nov 30 Javascript
原生js实现3D轮播图
Mar 21 Javascript
vue中解决chrome浏览器自动播放音频和MP3语音打包到线上的实现方法
Oct 09 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
Discuz板块横排显示图片的实现方法
2007/05/28 PHP
php抓取页面与代码解析 推荐
2010/07/23 PHP
php float不四舍五入截取浮点型字符串方法总结
2013/10/28 PHP
PHP微信开发之有道翻译
2016/06/23 PHP
PHP简单判断iPhone、iPad、Android及PC设备的方法
2016/10/11 PHP
php源码之将图片转化为data/base64数据流实例详解
2016/11/27 PHP
php制作基于xml的RSS订阅源功能示例
2017/02/08 PHP
PHP设计模式之工厂模式定义与用法详解
2018/04/03 PHP
PHP封装的验证码工具类定义与用法示例
2018/08/22 PHP
Swoole源码中如何查询Websocket的连接问题详解
2020/08/30 PHP
IE浏览器PNG图片透明效果代码
2008/09/02 Javascript
30个最佳jQuery Lightbox效果插件分享
2011/04/11 Javascript
javascript时间自动刷新实现原理与步骤
2013/01/06 Javascript
利用try-catch判断变量是已声明未声明还是未赋值
2014/03/12 Javascript
JS实现屏蔽shift,Ctrl,alt等功能键的方法
2015/06/01 Javascript
js实现可折叠展开的手风琴菜单效果
2015/09/07 Javascript
js获取鼠标点击的对象,点击另一个按钮删除该对象的实现代码
2016/05/13 Javascript
全面解析Bootstrap中tooltip、popover的使用方法
2016/06/13 Javascript
微信小程序 PHP生成带参数二维码
2017/02/21 Javascript
js实现多张图片延迟加载效果
2017/07/17 Javascript
Bootstrap与Angularjs的模态框实例代码
2017/08/03 Javascript
安装vue-cli报错 -4058 的解决方法
2017/10/19 Javascript
微信小程序Page中data数据操作和函数调用方法
2019/05/08 Javascript
微信小程序 点击切换样式scroll-view实现代码实例
2019/10/11 Javascript
Python实现将n个点均匀地分布在球面上的方法
2015/03/12 Python
解决Python中由于logging模块误用导致的内存泄露
2015/04/23 Python
MySQL中表的复制以及大型数据表的备份教程
2015/11/25 Python
python 内置函数filter
2017/06/01 Python
Django查询数据库的性能优化示例代码
2017/09/24 Python
python 请求服务器的实现代码(http请求和https请求)
2018/05/25 Python
OpenCV读取与写入图片的实现
2020/10/13 Python
以太网Ethernet IEEE802.3
2013/08/05 面试题
4s店市场专员岗位职责
2014/04/09 职场文书
土木工程求职信
2014/05/29 职场文书
JS实现简单控制视频播放倍速的实例代码
2021/04/18 Javascript
CSS实现鼠标悬浮动画特效
2023/05/07 HTML / CSS