前言

Angular 2 中 Components 之間的關係示意層一層的,就長得向下面這張圖。

每個格子就是一個組件,資訊向下傳遞很容易,而為了維護資料傳遞的單一性,向上傳遞需要觸發事件 (event)。所以現在當 child component 需要被 parents 知道的時候,child 會被 parents 觸發事件。parent component 會採取任何可能的行為來串聯他底下的組件,通常就是單方向往下資訊傳遞。藉由區隔向上和向下的資料傳遞,事情就變得比較簡單和比較好管理。

@Input() & inputs

@Input 的目的是確認資料綁定 input 特性 (properties)是可以在改變時被追蹤的。基本上來說,它是 Angular 將 DOM 藉由特性綁定 (property bindings) 直接在組件注入數值的方法。

講了這麼多還是不太懂?還是直接看 Code 吧! 先看看 Plunker 範例吧!

AppComponent 長這樣,可以看到裡面有兩個 Components:HelloComponentGoodbyeComponent

// app/app.component.ts

import {Component, Input} from 'angular2/core';
import HelloComponent from './hello.component';
import GoodbyeComponent from './goodbye.component';

@Component({
selector: 'app',
template: <div> <hello-component [myName]="name"></hello-component> <hello-component myName="Other World"></hello-component> <goodbye-component [myName]="name"></goodbye-component> <goodbye-component myName="Your World"></goodbye-component> </div>,
directives: [HelloComponent, GoodbyeComponent]
})
export class App {
name: string;

constructor() {
this.name = "World";
}
}

先告訴大家顯示結果會是

Hello, World!

Hello, Other World!

Good Bye, World!

Good Bye, Your World!

先來看看另外兩個 Components 裡面是甚麼

// app/hello.component.ts

import {Component, Input} from 'angular2/core';

@Component({
selector: 'hello-component',
template: '<p>Hello, {{myName}}!</p>',
inputs: ['myName']
})
export default class HelloComponent {
myName: string;

constructor() {}
}

// app/goodbye.component.ts

import {Component, Input} from 'angular2/core';

@Component({
	selector: 'goodbye-component',
	template: '<p>Good Bye, {{myName}}!</p>',
})
export default class GoodbyeComponent {
  @Input()
  myName: string;
  
  constructor() {}
}

大家來找碴,找到不一樣的地方了嗎?

...
@Component({
	selector: 'hello-component',
	template: '<p>Hello, {{myName}}!</p>',
	inputs: ['myName']
})
...
...
export default class GoodbyeComponent {
  @Input()
  myName: string;
  ...
}

一個是放在 @Component 裡面加入 inputs,一個則是在 export 加入 @Input,其實兩個方法都可以,從範例可以看到 Hello 和 GoodBye 分別採用這兩種方法,都可以成功執行。

所以 @Input() 是啥?

回到 AppComponent

template: `<div>
            <hello-component [myName]="name"></hello-component>
            <hello-component myName="Other World"></hello-component>
            <goodbye-component [myName]="name"></goodbye-component>
            <goodbye-component myName="Your World"></goodbye-component>
          </div>`,

selector 裡面我們有看到 myName,這個就是「向下」連結的意思,剛剛我們在 @Input() 後面宣告 myName 就是告訴 Child 他的 Parent 會呼叫他。

  ...
  @Input()
  myName: string;
  ...

[myname]="thisName" 如果這樣寫代表 Child 的值和當前這個 Component 的 thisName 這個變數做綁定,如果 myname="Something" 則是直接將 "Something" 這串值指定給 Child。

@Output() & outputs

@Output是用來觸發組件的客製化事件並提供一個通道讓組件之間彼此溝通。
一樣先看看 Plunker 範例吧!

@Output()outputs 狀況跟 @Input()inputs 一樣,就不重複說明了。

現在來理解甚麼是 @Output() 吧!
剛剛說過 @Input 是由上到下的概念,就是 Parent 給定甚麼,Child 就會有甚麼。
@Output 不一樣,是由下影響上,意思就是 Child 先有變化,進而改變了 Parent。
這個範例就是由 Child 的按鈕執行 Child 的函數,進而回傳給 Parent,Parent 的值才改變。

P.S. 這邊分別用到三種綁定方式,用看得比較快,就不說明了