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 相关文章推荐
表单的一些基本用法与技巧
Jul 15 Javascript
基于Jquery的标签智能验证实现代码
Dec 27 Javascript
在JavaScript中操作时间之getYear()方法的使用教程
Jun 11 Javascript
使用js获取地址栏参数的方法推荐(超级简单)
Jun 14 Javascript
js 动态添加元素(div、li、img等)及设置属性的方法
Jul 19 Javascript
扩展Bootstrap Tooltip插件使其可交互的方法
Nov 07 Javascript
javascript history对象详解
Feb 09 Javascript
详解windows下vue-cli及webpack 构建网站(二)导入bootstrap样式
Jun 17 Javascript
vue 标签属性数据绑定和拼接的实现方法
May 17 Javascript
vue-cli初始化项目中使用less的方法
Aug 09 Javascript
Vue动态获取width的方法
Aug 22 Javascript
全面解析vue router 基本使用(动态路由,嵌套路由)
Sep 02 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
风味层面去分析咖啡油脂
2021/03/03 咖啡文化
phpwind中的数据库操作类
2007/01/02 PHP
php中截取中文字符串的代码小结
2011/07/17 PHP
juqery 学习之四 筛选查找
2010/11/30 Javascript
js jquery ajax的几种用法总结(及优缺点介绍)
2014/01/28 Javascript
jquery使用jxl插件导出excel示例
2014/04/14 Javascript
js中数组结合字符串实现查找(屏蔽广告判断url等)
2016/03/30 Javascript
jQuery web 组件 后台日历价格、库存设置的代码
2016/10/14 Javascript
URL的参数中有加号传值变为空格的问题(URL特殊字符)
2016/11/04 Javascript
js手机号4位显示空格,银行卡每4位显示空格效果
2017/03/23 Javascript
bootstrap3 dialog 更强大、更灵活的模态框
2017/04/20 Javascript
vue.js全局API之nextTick全面解析
2017/07/07 Javascript
荐书|您有一份JavaScript书单待签收
2017/07/21 Javascript
JS脚本实现网页自动秒杀点击
2018/01/11 Javascript
通过vue-router懒加载解决首次加载时资源过多导致的速度缓慢问题
2018/04/08 Javascript
深入理解Vue 的钩子函数
2018/09/05 Javascript
10种检测Python程序运行时间、CPU和内存占用的方法
2015/04/01 Python
按日期打印Python的Tornado框架中的日志的方法
2015/05/02 Python
python 实现UTC时间加减的方法
2018/12/31 Python
解决pycharm 工具栏Tool中找不到Run manager.py Task的问题
2019/07/01 Python
Pycharm中出现ImportError:DLL load failed:找不到指定模块的解决方法
2019/09/17 Python
python retrying模块的使用方法详解
2019/09/25 Python
python使用协程实现并发操作的方法详解
2019/12/27 Python
Python如何操作docker redis过程解析
2020/08/10 Python
termux中matplotlib无法显示中文问题的解决方法
2021/01/11 Python
CSS3实现水平居中、垂直居中、水平垂直居中的实例代码
2020/02/27 HTML / CSS
日本快乐生活方式购物网站:Shop Japan
2018/07/17 全球购物
澳大利亚便宜隐形眼镜购买网站:QUICKLENS Australia
2018/10/06 全球购物
哥伦比亚加拿大官网:Columbia Sportswear Canada
2020/09/07 全球购物
Vans(范斯)新西兰官方网站:美国原创极限运动品牌
2020/09/19 全球购物
投标服务承诺书
2014/05/28 职场文书
王金山在党的群众路线教育实践活动总结大会上的讲话稿
2014/10/25 职场文书
2015年度考核个人工作总结
2015/10/24 职场文书
分家协议书范本
2016/03/22 职场文书
创业计划书之物流运送
2019/09/17 职场文书
python小型的音频操作库mp3Play
2022/04/24 Python