angular组件通信是很长常见的功能,现在总结下,常见通信主要用一下三种
- 父组件 => 子组件
- 子组件 => 父组件
-
组件A = > 组件B
父组件 => 子组件 | 子组件 => 父组件 | sibling => sibling |
---|---|---|
@input | @output | |
setters (本质上还是@input) | 注入父组件 | |
ngOnChanges() (不推荐使用) | ||
局部变量 | ||
@ViewChild() | ||
service | service | service |
Rxjs的Observalbe | Rxjs的Observalbe | Rxjs的Observalbe |
localStorage,sessionStorage | localStorage,sessionStorage | localStorage,sessionStorage |
上面图表总结了能用到通信方案,期中最后3种,是通用的,angular的组件之间都可以使用这3种,其中Rxjs是最最牛逼的用法,甩redux,promise,这些同样基于函数式的状态管理几条街,下面一一说来
父组件 => 子组件
@input,最常用的一种方式
@Component({
selector: 'app-parent',
template: 'childText: ',
styleUrls: ['./parent.component.css']
})
export class ParentComponent implements OnInit {
varString: string;
constructor() { }
ngOnInit() {
this.varString = '从父组件传过来的' ;
}
}
import { Component, OnInit, Input } from '@angular/core';
@Component({
selector: 'app-child',
template: '{{textContent}}
',
styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit {
@Input() public textContent: string ;
constructor() { }
ngOnInit() {
}
}
setter
setter 是拦截@input 属性,因为我们在组件通信的时候,常常需要对输入的属性处理下,就需要setter了,setter和getter常配套使用,稍微修改下上面的child.component.ts
child.component.ts
import { Component, OnInit, Input } from '@angular/core';
@Component({
selector: 'app-child',
template: '{{textContent}}
',
styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit {
_textContent:string;
@Input()
set textContent(text: string){
this._textContent = !text: "啥都没有给我" ? text ;
} ;
get textContent(){
return this._textContent;
}
constructor() { }
ngOnInit() {
}
}
onChange
这个是通过angular生命周期钩子来检测,不推荐使用,要使用的话可以参angular文档
@ViewChild()
@ViewChild() 一般用在调用子组件非私有的方法
import {Component, OnInit, ViewChild} from '@angular/core';
import {ViewChildChildComponent} from "../view-child-child/view-child-child.component";
@Component({
selector: 'app-parent',
templateUrl: './parent.component.html',
styleUrls: ['./parent.component.css']
})
export class ParentComponent implements OnInit {
varString: string;
@ViewChild(ViewChildChildComponent)
viewChildChildComponent: ViewChildChildComponent;
constructor() { }
ngOnInit() {
this.varString = '从父组件传过来的' ;
}
clickEvent(clickEvent: any) {
console.log(clickEvent);
this.viewChildChildComponent.myName(clickEvent.value);
}
}
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-view-child-child',
templateUrl: './view-child-child.component.html',
styleUrls: ['./view-child-child.component.css']
})
export class ViewChildChildComponent implements OnInit {
constructor() { }
name: string;
myName(name: string) {
console.log(name);
this.name = name ;
}
ngOnInit() {
}
}
局部变量
局部变量和viewChild类似,只能用在html模板里,修改parent.component.html,通过#viewChild
这个变量来表示子组件,就能调用子组件的方法了.
child 组件如下
@Component({
selector: 'app-view-child-child',
templateUrl: './view-child-child.component.html',
styleUrls: ['./view-child-child.component.css']
})
export class ViewChildChildComponent implements OnInit {
constructor() { }
name: string;
myName(name: string) {
console.log(name);
this.name = name ;
}
ngOnInit() {
}
}
子组件 => 父组件
@output()
output这种常见的通信,本质是给子组件传入一个function
,在子组件里执行完某些方法后,再执行传入的这个回调function
,将值传给父组件
parent.component.ts
@Component({
selector: 'app-child-to-parent',
templateUrl: './parent.component.html',
styleUrls: ['./parent.component.css']
})
export class ChildToParentComponent implements OnInit {
childName: string;
childNameForInject: string;
constructor( ) { }
ngOnInit() {
}
showChildName(name: string) {
this.childName = name;
}
}
parent.component.html
output方式 childText:{{childName}}
child.component.ts
export class OutputChildComponent implements OnInit {
// 传入的回调事件
@Output() public childNameEventEmitter: EventEmitter = new EventEmitter();
constructor() { }
ngOnInit() {
}
showMyName(value) {
//这里就执行,父组件传入的函数
this.childNameEventEmitter.emit(value);
}
}
注入父组件
这个原理的原因是父,子组件本质生命周期是一样的
export class OutputChildComponent implements OnInit {
// 注入父组件
constructor(private childToParentComponent: ChildToParentComponent) { }
ngOnInit() {
}
showMyName(value) {
this.childToParentComponent.childNameForInject = value;
}
}
sibling组件 => sibling组件
service
Rxjs
通过service通信
angular中service是单例的,所以三种通信类型都可以通过service,很多前端对单例理解的不是很清楚,本质就是
,你在某个module中注入service,所有这个modul的component都可以拿到这个service的属性,方法,是共享的,所以常在app.moudule.ts注入日志service,http拦截service,在子module注入的service,只能这个子module能共享,在component注入的service,就只能子的component的能拿到service,下面以注入到app.module.ts,的service来演示
user.service.ts
@Injectable()
export class UserService {
age: number;
userName: string;
constructor() { }
}
app.module.ts
@NgModule({
declarations: [
AppComponent,
SiblingAComponent,
SiblingBComponent
],
imports: [
BrowserModule
],
providers: [UserService],
bootstrap: [AppComponent]
})
export class AppModule { }
SiblingBComponent.ts
@Component({
selector: 'app-sibling-b',
templateUrl: './sibling-b.component.html',
styleUrls: ['./sibling-b.component.css']
})
export class SiblingBComponent implements OnInit {
constructor(private userService: UserService) {
this.userService.userName = "王二";
}
ngOnInit() {
}
}
SiblingAComponent.ts
@Component({
selector: 'app-sibling-a',
templateUrl: './sibling-a.component.html',
styleUrls: ['./sibling-a.component.css']
})
export class SiblingAComponent implements OnInit {
userName: string;
constructor(private userService: UserService) {
}
ngOnInit() {
this.userName = this.userService.userName;
}
}
通过Rx.js通信
这个是最牛逼的,基于订阅发布的这种流文件处理,一旦订阅,发布的源头发生改变,订阅者就能拿到这个变化;这样说不是很好理解,简单解释就是,b.js,c.js,d.js订阅了a.js里某个值变化,b.js,c.js,d.js立马获取到这个变化的,但是a.js并没有主动调用b.js,c.js,d.js这些里面的方法,举个简单的例子,每个页面在处理ajax请求的时候,都有一弹出的提示信息,一般我会在
组件的template中中放一个提示框的组件,这样很繁琐每个组件都要来一次,如果基于Rx.js,就可以在app.component.ts中放这个提示组件,然后app.component.ts订阅公共的service,就比较省事了,代码如下
首先搞一个alset.service.ts
import {Injectable} from "@angular/core";
import {Subject} from "rxjs/Subject";
@Injectable()
export class AlertService {
private messageSu = new Subject(); //
messageObserve = this.messageSu.asObservable();
private setMessage(message: string) {
this.messageSu.next(message);
}
public success(message: string, callback?: Function) {
this.setMessage(message);
callback();
}
}
sibling-a.component.ts
@Component({
selector: 'app-sibling-a',
templateUrl: './sibling-a.component.html',
styleUrls: ['./sibling-a.component.css']
})
export class SiblingAComponent implements OnInit {
userName: string;
constructor(private userService: UserService, private alertService: AlertService) {
}
ngOnInit() {
this.userName = this.userService.userName;
// 改变alertService的信息源
this.alertService.success("初始化成功");
}
}
app.component.ts
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'app';
message: string;
constructor(private alertService: AlertService) {
//订阅alertServcie的message服务
this.alertService.messageObserve.subscribe((res: any) => {
this.message = res;
});
}
}
这样订阅者就能动态的跟着发布源变化.
总结: 以上就是常用的的通信方式,各种场景可以采取不同的方法
demo:https://github.com/hucheng91/angular2Learn/tree/master/angualar-component-communication
我的博客:http://blog.vinlineskater.com/