angular2组件通讯的几种方式
最近刚刚接触angular2,对ng2也是一知半解,如有说得不对的地方欢迎指出,欢迎加q共同探讨学习991085978;
1.通过输入型绑定把数据从父组件传到子组件
HeroChildComponent
有两个输入型属性,它们通常带@Input装饰器。
第二个@Input
为子组件的属性名masterName
指定一个别名master,父组件
HeroParentComponent
把子组件的HeroChildComponent
放到*ngFor
循环器中,把自己的master
字符串属性绑定到子组件的master
别名上,并把每个循环的hero
实例绑定到子组件的hero
属性。
2.通过setter截听输入属性值的变化
使用一个输入属性的setter,以拦截父组件中值的变化,并采取行动。(注意是输入型属性)
子组件NameChildComponent
的输入属性name
上的这个setter,会trim掉名字里的空格,并把空值替换成默认字符串。
下面的NameParentComponent
展示了各种名字的处理方式,包括一个全是空格的名字。
运行结果:
3.通过ngOnChanges来截听输入属性值的变化
使用OnChanges
生命周期钩子接口的ngOnChanges
方法来监测输入属性值的变化并做出回应。(当需要监视多个、交互式输入属性的时候,本方法比用属性的setter更合适)
这个VersionChildComponent
会监测输入属性major
和minor
的变化,并把这些变化编写成日志以报告这些变化。
VersionParentComponent
提供minor
和major
值,把修改它们值的方法绑定到按钮上。
这样子便能实现组件间的通讯
4.父组件监听子组件的事件
子组件暴露一个EventEmitter
属性,当事件发生时,子组件利用该属性emits
(向上弹射)事件。父组件绑定到这个事件属性,并在事件发生时作出回应。
子组件的EventEmitter
属性是一个输出属性,通常带有@Output装饰器,就像在VoterComponent
中看到的。
点击按钮会触发true
或false
(布尔型有效载荷)的事件。
父组件VoteTakerComponent
绑定了一个事件处理器(onVoted
),用来响应子组件的事件($event
)并更新一个计数器。
5.父组件与子组件通过本地变量互动
父组件不能使用数据绑定来读取子组件的属性或调用子组件的方法。但可以在父组件模板里,新建一个本地变量来代表子组件,然后利用这个变量来读取子组件的属性和调用子组件的方法,如下例所示。
子组件CountdownTimerComponent
进行倒计时,归零时发射一个导弹。start
和stop
方法负责控制时钟并在模板里显示倒计时的状态信息。
让我们来看看计时器组件的宿主组件CountdownLocalVarParentComponent
。
父组件不能通过数据绑定使用子组件的start
和stop
方法,也不能访问子组件的seconds
属性。
把本地变量(#timer
)放到(<countdown-timer>
)标签中,用来代表子组件。这样父组件的模板就得到了子组件的引用,于是可以在父组件的模板中访问子组件的所有属性和方法。
在这个例子中,我们把父组件的按钮绑定到子组件的start
和stop
方法,并用插值表达式来显示子组件的seconds
属性。
6.父组件调用ViewChild
这个本地变量方法是个简单便利的方法。但是它也有局限性,因为父组件-子组件的连接必须全部在父组件的模板中进行。父组件本身的代码对子组件没有访问权。
如果父组件的类需要读取子组件的属性值或调用子组件的方法,就不能使用本地变量方法。
当父组件类需要这种访问时,可以把子组件作为ViewChild,注入到父组件里面。
我们将会用同一个倒计时范例来解释这种技术。我们没有改变它的样子或行为。子组件CountdownTimerComponent也和原来一样。
由本地变量切换到ViewChild技术的唯一目的就是做示范。
下面是父组件CountdownViewChildParentComponent
:
把子组件的视图插入到父组件类需要做一点额外的工作。
需要通过ViewChild
装饰器导入这个引用,并挂上AfterViewInit
生命周期钩子。
通过@ViewChild
属性装饰器,将子组件CountdownTimerComponent
注入到私有属性timerComponent
里面。
组件元数据里就不再需要#timer
本地变量了。而是把按钮绑定到父组件自己的start
和stop
方法,使用父组件的seconds
方法的插值表达式来展示秒数变化。
这些方法可以直接访问被注入的计时器组件。
ngAfterViewInit
生命周期钩子是非常重要的一步。被注入的计时器组件只有在Angular显示了父组件视图之后才能访问,所以我们先把秒数显示为0.
然后Angular会调用ngAfterViewInit
生命周期钩子,但这时候再更新父组件视图的倒计时就已经太晚了。Angular的单向数据流规则会阻止在同一个周期内更新父组件视图。我们在显示秒数之前会被迫再等一轮。
使用setTimeout
来等下一轮,然后改写seconds
方法,这样它接下来就会从注入的这个计时器组件里获取秒数的值。
7.父组件和子组件通过服务来通讯
父组件和它的子组件共享同一个服务,利用该服务在家庭内部实现双向通讯。
该服务实例的作用域被限制在父组件和其子组件内。这个组件子树之外的组件将无法访问该服务或者与它们通讯。
这个MissionService
把MissionControlComponent
和多个AstronautComponent
子组件连接起来。
MissionControlComponent
提供服务的实例,并将其共享给它的子组件(通过providers
元数据数组),子组件可以通过构造函数将该实例注入到自身。
AstronautComponent
也通过自己的构造函数注入该服务。由于每个AstronautComponent
都是MissionControlComponent
的子组件,所以它们获取到的也是父组件的这个服务实例。
注意,通过subscription
服务订阅任务,并在AstronautComponent
被销毁的时候退订。这是一个用于防止内存泄漏的保护措施。实际上,在这个应用程序中并没有这个风险,因为AstronautComponent
的生命期和应用程序的生命期一样长。但在更复杂的应用程序环境中就不一定了。
不需要在MissionControlComponent
中添加这个保护措施,因为作为父组件,它控制着MissionService
的生命期。