Angular2 组件通信的实例代码


Posted in Javascript onJune 23, 2017

1. 组件通信

我们知道Angular2应用程序实际上是有很多父子组价组成的组件树,因此,了解组件之间如何通信,特别是父子组件之间,对编写Angular2应用程序具有十分重要的意义,通常来讲,组件之间的交互方式主要有如下几种:

  1. 使用输入型绑定,把数据从父组件传到子组件
  2. 通过 setter 拦截输入属性值的变化
  3. 使用 ngOnChanges 拦截输入属性值的变化
  4. 父组件监听子组件的事件
  5. 父组件与子组件通过本地变量互动
  6. 父组件调用 ViewChild
  7. 父组件和子组件通过服务来通讯

本文会通过讲解着几种方式来对组件之间的通信做一个大致的介绍。

2. 输入型绑定

输入型绑定指的是利用模板语法中的属性型绑定方式,将父组件的数据传递到子组件对应的对象中,子组件中的对象一般使用@Input装饰器来修饰,作为数据的接受者,例如

@Component({

selector: 'child',

template: 'I am fron {{input}}'

})

export class ChildComponent implements OnInit {

@Input()

input;

constructor() { }

ngOnInit() { }

}

@Component({

selector: 'parent',

template: '<child [input]="data"></child>'

})

export class ParentComponent implements OnInit {

data: string;

constructor() { }

ngOnInit() {

this.data = "parent";

}

}

 以上的例子我们可以看出,存在父子两个组件,在父组件ParentComponent中的模板中引入了<child [input]="data"></child>子组件,并将data数据通过属性绑定的方式绑定到input属性中传入到子组件中,子组件中通过@Input()注解修饰input属性来接收传入的数据,并显示在模板I am fron {{input}}中。

输入型绑定是从父组件传递数据到子组件最常见的方式。

3. setter监听

我们知道,Angular2是一个MVVM的框架,当数据发生变化时能够同步显示到模板视图中,可以使用一个输入属性的 setter 函数,以拦截父组件中值的变化,并采取行动。例如,我们改造上面的例子,子组件中使用set,get重写对应的绑定input属性,当输入值方式变化时输出一个控制台信息。

@Component({

selector: 'child',

template: 'I am fron {{data}}'

})

export class ChildComponent implements OnInit {

_input:string;

@Input()

public set input(v : string) {

this._input = v;

console.log(v);

}

public get input() : string {

return this._input;

}

constructor() { }

ngOnInit() { }

}

 4. ngOnChanges

除了上面说的setter函数可以响应输入数据的变化外,Angular2还提供了一个生命周期函数ngOnChanges 可以监听数据的变化。使用 OnChanges 生命周期钩子接口的 ngOnChanges 方法来监测输入属性值的变化并做出回应。我们改造以上的子组件来响应对应的变化,在这个示例中,我们监听了输入数据的变化,采取的对应动作仅仅是输出对应的信息,当然你也可以做很多其他的事情。

@Component({

selector: 'child',

template: 'I am fron {{data}}'

})

export class ChildComponent implements OnInit, OnChanges {

_input: string;

@Input()

public set input(v: string) {

this._input = v;

console.log(v);

}

public get input(): string {

return this._input;

}

constructor() { }

ngOnInit() { }

ngOnChanges(changes: SimpleChanges) {

console.log(changes);

}

}

 5. 事件传播

上面的集中方式都是父组件如何向子组件传递数据以及子组件如何监听数据的变化,事件传播则是子组件如何向父组件通信的一种方式。子组件暴露一个 EventEmitter 属性,当事件发生时,子组件利用该属性 emits( 向上弹射 ) 事件。父组件绑定到这个事件属性,并在事件发生时作出回应。子组件的 EventEmitter 属性是一个 输出属性 ,通常带有 @Output 装饰器 。

@Component({

selector: 'child',

template: `

I am fron {{data}}<br />

<button id="out" (click)="click()">click for out</button>

`

})

export class ChildComponent implements OnInit, OnChanges {

_input: string;

@Input()

public set input(v: string) {

this._input = v;

console.log(v);

}

public get input(): string {

return this._input;

}

@Output()

output:EventEmitter<string> = new EventEmitter<string>();

click(){

this.output.emit("i am from child");

}

constructor() { }

ngOnInit() { }

ngOnChanges(changes: SimpleChanges) {

console.log(changes);

}

}

@Component({

selector: 'parent',

template: '<child [input]="data" (output)="output($event)"></child>'

})

export class ParentComponent implements OnInit {

data: string;

constructor() { }

ngOnInit() {

this.data = "parent";

}

output($event){

console.log($event);

}

}

 在上面的例子中,我们在子组件ChildComponent添加了一个向外传播的事件output:EventEmitter<string> = new EventEmitter<string>(),并添加了一个点击的按钮,当按钮事件触发时,就会调用output事件向父组件传递事件,并将数据作为参数传递到父组件ParentComponent中,同时在父组件ParentComponent的模板<child [input]="data" (output)="output($event)"></child>中可以看到,我们使用模板语法中的事件绑定,绑定了output函数作为对应事件的接受函数,当子组件output事件触发是,父组件的函数就会得到执行。

使用事件传播来进行子组件对父组件之间的通信是最常见的方式。

6. 本地变量

在模板语法中,我们知道存在着本地变量这种语法,可以使用本地变量来代表对应的组件。虽然父组件不能使用数据绑定来读取子组件的属性或调用子组件的方法。但可以在父组件模板里,新建一个本地变量来代表子组件,然后利用这个变量来读取子组件的属性和调用子组件的方法,不过这种使用方式只能在模板中使用,例如如下所示,改写上面例子中的父组件模板,代码如下。

我们在ParentComponent组件中使用本地变量#child获取了child组件的实例,这样就可以在模板中使用其属性或者方法,例如child.input。

@Component({

selector: 'parent',

template: '<child [input]="data" (output)="output($event)" #child></child>{{child.input}}'

})

export class ParentComponent implements OnInit {

data: string;

constructor() { }

ngOnInit() {

this.data = "parent";

}

output($event){

console.log($event);

}

}

7. ViewChild

本地变量的方式是在父组件的模板中获取子组件的实例,有木有其他方式可以在组件的类中获取子组件的实例呢?答案是肯定的,如果父组件的类需要读取子组件的属性值或调用子组件的方法,就不能使用本地变量方法。当父组件类 需要这种访问时,可以把子组件作为ViewChild,注入到父组件里面。例如,我们改造上面的父组件的组件类,使用ViewChild来获取子组件的实例,代码如下:

@Component({

selector: 'parent',

template: '<child [input]="data" (output)="output($event)" #child></child>{{child.input}}'

})

export class ParentComponent implements OnInit {

@ViewChild(ChildComponent)

private childComponent: ChildComponent;

data: string;

constructor() { }

ngOnInit() {

this.data = "parent";

}

output($event) {

console.log($event);

}

}

 在以上的代码中,我们使用@ViewChild(ChildComponent)注解的形式获取了对应子组件childComponent的实例,这样在父组件类中就可以调用子组件对应的属性及方法了。

相对于本地变量的方式而言,ViewChild的方式更加灵活,用途也比较广泛。但是,需要注意的一点是,必须等待父组件的视图显示完成后才可以使用,因此,ngAfterViewInit 生命周期钩子是非常重要的一步。

8. 服务方式

通过服务依赖注入的方式,我们可以了解到,服务在父子组件之间是可以共享的,因此,我们可以利用共享的服务的形式在父子组件之间进行通信。

如果我们将服务实例的作用域被限制在父组件和其子组件内,这个组件子树之外的组件将无法访问该服务或者与它们通讯。

一般来说,父子之间使用服务的方式来通行,是采用事件消息的形式来实现的。

例如,如下的代码中,父子组件中共享了Service服务,并在各自的类中获取了Service服务的实例,当分别点击父子组件中的按钮时,就能够触发Service服务中的对应的input$以及output$,因为服务是共享的,所以在父子组件中监听对应的服务信息,就能够得到传递的消息。

@Injectable()

export class Service {

input$: EventEmitter<string> = new EventEmitter<string>();

output$: EventEmitter<string> = new EventEmitter<string>();

constructor() {

}

}

@Component({

selector: 'child',

template: `

<button id="out" (click)="click()">click for output</button>

`

})

export class ChildComponent {

constructor(private _service: Service) {

this._service.input$.subscribe(function (input: string) {

console.log(input);

})

}

click() {

this._service.output$.emit('i am from child');

}

}

@Component({

selector: 'parent',

template: '<child></child><button id="input" (click)="click()">click for input</button>',

providers: [Service]

})

export class ParentComponent {

constructor(private _service: Service) {

this._service.output$.subscribe(function (output: string) {

console.log(output);

})

}

click() {

this._service.input$.emit('i am from child');

}

}

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

Javascript 相关文章推荐
JavaScript之Getters和Setters 平台支持等详细介绍
Dec 07 Javascript
javascript错误的认识不用关心内存管理
Dec 15 Javascript
jquery实现metro效果示例代码
Sep 06 Javascript
js实现带缓冲效果的仿QQ面板折叠菜单代码
Sep 06 Javascript
JQuery标签页效果的两个实例讲解(4)
Sep 17 Javascript
在javascript中随机数 math random如何生成指定范围数值的随机数
Oct 21 Javascript
jQuery实现分隔条左右拖动功能
Nov 21 Javascript
基于ajax与msmq技术的消息推送功能实现代码
Dec 26 Javascript
Vue-Cli中自定义过滤器的实现代码
Aug 12 Javascript
你应该了解的JavaScript Array.map()五种用途小结
Nov 14 Javascript
使用element-ui +Vue 解决 table 里包含表单验证的问题
Jul 17 Javascript
一文读懂vue动态属性数据绑定(v-bind指令)
Jul 20 Javascript
js实现文字列表无缝滚动效果
Jun 23 #Javascript
jquery图片放大镜效果
Jun 23 #jQuery
Avalonjs双向数据绑定与监听的实例代码
Jun 23 #Javascript
JS失效 提示HTML1114: (UNICODE 字节顺序标记)的代码页 utf-8 覆盖(META 标记)的冲突的代码页 utf-8
Jun 23 #Javascript
微信小程序与php 实现微信支付的简单实例
Jun 23 #Javascript
jquery单击文字或图片内容放大并居中显示
Jun 23 #jQuery
详解webpack异步加载业务模块
Jun 23 #Javascript
You might like
解析func_num_args与func_get_args函数的使用
2013/06/24 PHP
ThinkPHP使用UTFWry地址库进行IP定位实例
2014/04/01 PHP
php邮件发送的两种方式
2020/04/28 PHP
浅谈PHP SHA1withRSA加密生成签名及验签
2019/03/18 PHP
大家未必知道的Js技巧收藏
2008/04/07 Javascript
学习ExtJS 访问容器对象
2009/10/07 Javascript
Javascript学习笔记4 Eval函数
2010/01/11 Javascript
为JavaScript添加重载函数的辅助方法
2010/07/04 Javascript
Javascript调用C#代码
2011/01/17 Javascript
[JSF]使用DataModel处理表行事件的实例代码
2013/08/05 Javascript
Chrome扩展页面动态绑定JS事件提示错误
2014/02/11 Javascript
node.js中的http.createClient方法使用说明
2014/12/15 Javascript
AngularJS + Node.js + MongoDB开发的基于高德地图位置的通讯录
2015/01/02 Javascript
非常实用的js验证框架实现源码 附原理方法
2016/06/08 Javascript
详解js的事件处理函数和动态创建html标记方法
2016/12/16 Javascript
在React 组件中使用Echarts的示例代码
2017/11/08 Javascript
vue中使用v-for时为什么不能用index作为key
2020/04/04 Javascript
[05:08]第一届“网鱼杯”DOTA2比赛精彩集锦
2014/09/05 DOTA
Python之time模块的时间戳,时间字符串格式化与转换方法(13位时间戳)
2019/08/12 Python
python实现抠图给证件照换背景源码
2019/08/20 Python
学习Django知识点分享
2019/09/11 Python
最小二乘法及其python实现详解
2020/02/24 Python
Spartoo芬兰:欧洲最大的网上鞋店
2016/08/28 全球购物
NFL加拿大官方网上商店:NHLShop.ca
2019/03/12 全球购物
亚洲领先的旅游体验市场:Voyagin
2019/11/23 全球购物
为什么要优先使用同步代码块而不是同步方法?
2013/01/30 面试题
技校教师求职简历的自我评价
2013/10/20 职场文书
大专生的学习自我评价
2013/12/04 职场文书
法学专业大学生实习自我鉴定
2014/10/05 职场文书
工作批评与自我批评范文
2014/10/16 职场文书
党员活动总结
2015/02/04 职场文书
2016年安全月活动总结
2016/04/06 职场文书
python 实现mysql自动增删分区的方法
2021/04/01 Python
CSS3新特性详解(五):多列columns column-count和flex布局
2021/04/30 HTML / CSS
MySQL索引失效的典型案例
2021/06/05 MySQL
Spring JPA 增加字段执行异常问题及解决
2022/06/10 Java/Android