天天看點

Angular 2 父子元件資料通信

如今的前端開發,都朝元件式開發模式靠攏,如果使用目前最流行的前端架構Angular和React開發應用,不可避免地需要開發元件,也就意味着我們需要考慮元件間的資料傳遞等問題,不過Angular 2已經為我們提供了很好的解決方案。

父元件和子元件

接觸過面向對象程式設計的開發者肯定不會對父子關系陌生,在Angular 2中子元件存在于父元件“體内”,并且父子元件可以通過一些管道進行通訊。

父元件向子元件傳入資料 – @Input

當我們着手開始開發一個元件時,第一件想到的應該就是為其傳入資料,畢竟我們期望元件為我們處理某些工作通常就需要給其提供“養料”,畢竟不能又讓馬兒跑,又不給馬兒吃草。Angular 2中子元件使用裝飾器

@Input

接收父元件傳入的資料:

// child-component.ts
import { OnInit, Component, Input } from '@angular/core';

@Component({
    selector: 'child-component',
    ...
})
export class ChildComponent implements OnInit {
    @Input
    count: number = ;

    ngOnInit() {
        console.log(this.count);    // 父元件内傳入的值或者我們自己設定的初始值0
    }

    increaseNumber() {
        this.count ++;
    }

    descreaseNumber() {
        this.count --;
    }
}
           

可以看到,我們使用裝飾器

@Input

修飾了count屬性,這就意味着

child-component

被使用時期望收到一個名為count的屬性,當然不屬于自己掌控的範圍内要小心行事,别人使用我們的元件時什麼情況都可能出現,是以我們為count設定了一個初始值,當父元件沒有給我們的count屬性傳值時,我們就取此初始值。

// father-component.ts
import { Component } from '@angular/core';
import { ChildComponent } from '../child-component/child-component';

@Component({
    template: `
        <child-component [count]='initialCount'></child-component>
    `,
    ...
})
export class FatherComponent {
    initialCount: number = 5;
}
           

父元件使用

child-component

時,為count屬性賦予初始值

initialCount

,即5,也就是說此時

ChildComponent

ngOnInit

方法中會列印出5。注意

[count]

文法辨別了資料流向:父元件流入子元件,即單向資料綁定。此時如果傳入的資料是基本資料類型,子元件中對數組做任何操作都不會影響到父元件,但如果傳入的不是基本資料類型,而是引用資料類型,則要格外注意子元件中對資料的操作可能會對父元件産生影響。

子元件通知父元件資料已處理完成 – @Output、EventEmitter

父元件傳入資料給子元件之後并不是萬事大吉了,就像父母養育孩子,供其讀書,但孩子需要把學習進度、考試成績等呈現給父母看(不管是否自願…),父元件也需要子元件在合适的時機通知自己資料已經處理好,可以檢閱了。而此時就需要使用@Output和EventEmitter了。

// father-component.ts
import { Component } from '@angular/core';
import { ChildComponent } from '../child-component/child-component';

@Component({
    template: `
        <child-component [count]='initialCount' (change)="countChange($event)"></child-component>
    `,
    ...
})
export class FatherComponent {
    initialCount: number = 5;

    countChange($event) {

    }
}
           

看看我們在父元件中加入了什麼東東:

1.

(change)

,看到這樣的文法第一時間就知道這是事件綁定,也就是說我們在父元件中監聽子元件的某些變化,并能夠在其變化時作出相關操作;

2.增加了

countChange

方法作為

change

事件的處理函數。

但是稍等,當我們為input标簽指定type、placeholder等屬性時,我們知道它們都已經被“實作了”,所謂“實作”,即這些屬性在input标簽上是有意義的。但是目前這裡我們為

child-component

指定了名為

change

的事件是沒意義的,因為其并未“實作”

change

事件,于是下一步我們就需要使用@Output和EventEmitter将其變得有意義:

// child-component.ts
import { Component, Input, Output, EventEmitter } from '@angular/core';

@Component({
    selector: 'child-component',
    ...
})
export class ChildComponent {
    @Input
    count: number = ;

    @Output
    change = new EventEmitter();

    increaseNumber() {
        this.count ++;
        this.change.emit(this.count);
    }

    descreaseNumber() {
        this.count --;
        this.change.emit(this.count);
    }
}
           

讓我們再來看看在子元件中增加了什麼東東:

1.使用裝飾器@Output修飾了

change

屬性,并為其賦了初值為EventEmitter的執行個體;

2.在

increaseNumber

descreaseNumber

方法修改了

count

屬性後,調用了

change

屬性的

emit

方法通知父元件。

此時,我們在

ChildComponent

中實作了

change

,于是父元件中為

child-component

綁定

change

事件也就有意義了:當子元件通知父元件時,父元件可以擷取到通知中攜帶的資料并進行下一步操作:

// father-component.ts
...
countChange($event) {
    this.initialCount = $event;
}
...
           

總結

不知道你有沒有發現,其實上面我們模拟了“雙向資料綁定”:父元件将資料傳入子元件,子元件改變資料時通知父元件進行“同步更新”。但是要注意其實資料流向是單向的,即資料是父元件單向流入子元件,父元件資料的更新是通過子元件的事件通知以後才被更新。也就是說其實在Angular 2中:雙向資料綁定 = 單向資料綁定 + 事件,以我們最熟悉的

ngModel

為例:

和下面的寫法是等價的:

同樣的,如果将我們的

child-component

元件寫作雙向資料綁定的形式即為:

參考文檔

了解Ionic 2之class及其修飾器@App、@Pipe

@Input官方文檔

@Output官方文檔

EventEmitter官方文檔

元件間通信