angular 組件通信

angular組件通信是很長常見的功能,現(xiàn)在總結(jié)下,常見通信主要用一下三種

  1. 父組件 => 子組件
  2. 子組件 => 父組件
  3. 組件A = > 組件B


    Screenshot.png-19.9kB
    Screenshot.png-19.9kB
父組件 => 子組件 子組件 => 父組件 sibling => sibling
@input @output
setters (本質(zhì)上還是@input) 注入父組件
ngOnChanges() (不推薦使用)
局部變量
@ViewChild()
service service service
Rxjs的Observalbe Rxjs的Observalbe Rxjs的Observalbe
localStorage,sessionStorage localStorage,sessionStorage localStorage,sessionStorage

上面圖表總結(jié)了能用到通信方案,期中最后3種,是通用的,angular的組件之間都可以使用這3種,其中Rxjs是最最牛逼的用法,甩redux,promise,這些同樣基于函數(shù)式的狀態(tài)管理幾條街,下面一一說來

父組件 => 子組件

@input,最常用的一種方式

@Component({
  selector: 'app-parent',
template: '<div>childText:<app-child  [textContent] = "varString"></app-child></div>',
  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: '<h1>{{textContent}}</h1>',
  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: '<h1>{{textContent}}</h1>',
  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() 一般用在調(diào)用子組件非私有的方法

           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這個變量來表示子組件,就能調(diào)用子組件的方法了.

<div class="panel-body">
    <input class="form-control" type="text" #viewChildInputName >
    <button class=" btn btn-primary" (click)="viewChild.myName(viewChildInputName.value)">局部變量傳值</button>
    <app-view-child-child #viewChild></app-view-child-child>
            </div>

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這種常見的通信,本質(zhì)是給子組件傳入一個function,在子組件里執(zhí)行完某些方法后,再執(zhí)行傳入的這個回調(diào)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

<div class="panel-body">
  <p>output方式 childText:{{childName}}</p>
  <br>
  <app-output-child (childNameEventEmitter)="showChildName($event)"></app-output-child>
</div>
  child.component.ts
  export class OutputChildComponent implements OnInit {
  // 傳入的回調(diào)事件
  @Output() public childNameEventEmitter: EventEmitter<any> = new EventEmitter();
  constructor() { }
  ngOnInit() {
  }
  showMyName(value) {
    //這里就執(zhí)行,父組件傳入的函數(shù)
    this.childNameEventEmitter.emit(value);
  }
}

注入父組件

這個原理的原因是父,子組件本質(zhì)生命周期是一樣的

export class OutputChildComponent implements OnInit {
  // 注入父組件
  constructor(private childToParentComponent: ChildToParentComponent) { }
  ngOnInit() {
  }
  showMyName(value) {
    this.childToParentComponent.childNameForInject = value;
  }
}

sibling組件 => sibling組件

service

Rxjs

通過service通信

angular中service是單例的,所以三種通信類型都可以通過service,很多前端對單例理解的不是很清楚,本質(zhì)就是
,你在某個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通信

這個是最牛逼的,基于訂閱發(fā)布的這種流文件處理,一旦訂閱,發(fā)布的源頭發(fā)生改變,訂閱者就能拿到這個變化;這樣說不是很好理解,簡單解釋就是,b.js,c.js,d.js訂閱了a.js里某個值變化,b.js,c.js,d.js立馬獲取到這個變化的,但是a.js并沒有主動調(diào)用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<string>();  //
  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服務(wù)
     this.alertService.messageObserve.subscribe((res: any) => {
      this.message = res;
    });
  }
}

這樣訂閱者就能動態(tài)的跟著發(fā)布源變化.

總結(jié): 以上就是常用的的通信方式,各種場景可以采取不同的方法

demo:https://github.com/hucheng91/angular2Learn/tree/master/angualar-component-communication
我的博客:http://blog.vinlineskater.com/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子特碳,更是在濱河造成了極大的恐慌丝里,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機胜茧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來牙捉,“玉大人竹揍,你說我怎么就攤上這事敬飒。” “怎么了芬位?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵无拗,是天一觀的道長。 經(jīng)常有香客問我昧碉,道長英染,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任被饿,我火速辦了婚禮四康,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘狭握。我一直安慰自己闪金,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布论颅。 她就那樣靜靜地躺著哎垦,像睡著了一般。 火紅的嫁衣襯著肌膚如雪恃疯。 梳的紋絲不亂的頭發(fā)上漏设,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天,我揣著相機與錄音今妄,去河邊找鬼郑口。 笑死,一個胖子當(dāng)著我的面吹牛盾鳞,可吹牛的內(nèi)容都是我干的犬性。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼雁仲,長吁一口氣:“原來是場噩夢啊……” “哼仔夺!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起攒砖,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎日裙,沒想到半個月后吹艇,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡昂拂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年受神,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片格侯。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡鼻听,死狀恐怖财著,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情撑碴,我是刑警寧澤撑教,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站醉拓,受9級特大地震影響伟姐,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜亿卤,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一愤兵、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧排吴,春花似錦秆乳、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至憋槐,卻和暖如春双藕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背阳仔。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工忧陪, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人近范。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓嘶摊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親评矩。 傳聞我的和親對象是個殘疾皇子叶堆,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容