Angular 在父子組件、指令之間共享數(shù)據(jù)

2022-06-29 10:38 更新

在父子指令及組件之間共享數(shù)據(jù)

Angular 中的一個常見模式就是在父組件和一個或多個子組件之間共享數(shù)據(jù)??梢杂?nbsp;?@Input()? 和 ?@Output()? 來實(shí)現(xiàn)這個模式。

本章包含代碼片段的可工作實(shí)例參閱現(xiàn)場演練 / 下載范例。

考慮以下層次結(jié)構(gòu):

<parent-component>
  <child-component></child-component>
</parent-component>

?<parent-component>? 充當(dāng)了 ?<child-component>? 的上下文。

?@Input()? 和 ?@Output()? 為子組件提供了一種與其父組件通信的方法。 ?@Input()? 允許父組件更新子組件中的數(shù)據(jù)。相反,?@Output()? 允許子組件向父組件發(fā)送數(shù)據(jù)。

把數(shù)據(jù)發(fā)送到子組件

子組件或指令中的 ?@Input()? 裝飾器表示該屬性可以從其父組件中獲取值。

input

要使用 ?@Input()?,就必須對父組件和子組件進(jìn)行配置。

配置子組件

要使用 ?@Input()? 裝飾器,首先要導(dǎo)入 ?Input?,然后用 ?@Input()? 裝飾該屬性,如下例所示。

import { Component, Input } from '@angular/core'; // First, import Input
export class ItemDetailComponent {
  @Input() item = ''; // decorate the property with @Input()
}

在這個例子中, ?@Input()? 會修飾屬性 ?item?,它的類型為 ?string?,但 ?@Input()? 屬性可以是任意類型,比如 ?number?、?string?、?boolean ?或 ?object?。?item ?的值來自父組件。

接下來,在子組件模板中添加以下內(nèi)容:

<p>
  Today's item: {{item}}
</p>

配置父組件

下一步是在父組件的模板中綁定該屬性。在這個例子中,父組件模板是 ?app.component.html? 。

  1. 使用子組件的 selector (?<app-item-detail>?) 作為父組件模板中的指令。
  2. 使用屬性綁定把子組件的 ?item ?屬性綁定到父組件的 ?currentItem ?屬性上。
  3. <app-item-detail [item]="currentItem"></app-item-detail>
  4. 在父組件類中,為 ?currentItem ?指定一個值:
  5. export class AppComponent {
      currentItem = 'Television';
    }

通過 ?@Input()?,Angular 把 ?currentItem ?的值傳給子組件,以便 ?item ?渲染為 ?Television ?。

下圖展示了這種結(jié)構(gòu):

input-diagram-target-source

方括號 ?[]? 中的目標(biāo)就是子組件中用 ?@Input()? 裝飾的那個屬性。綁定源(等號的右邊部分)則是父組件傳給內(nèi)嵌組件的數(shù)據(jù)。

監(jiān)視 @Input() 的變更

要想監(jiān)視 ?@Input()? 屬性的變化,可以用 Angular 的生命周期鉤子?OnChanges ?。

把數(shù)據(jù)發(fā)送到父組件

子組件或指令中的 ?@Output()? 裝飾器允許數(shù)據(jù)從子組件傳給父組件。

output

?@Output()? 在子組件中標(biāo)記了一個屬性,作為數(shù)據(jù)從子組件傳遞到父組件的途徑。

子組件使用 ?@Output()? 屬性來引發(fā)事件,以通知父組件這一變化。為了引發(fā)事件, ?@Output()? 必須是 ?EventEmitter ?類型,它是 ?@angular/core? 中用來發(fā)出自定義事件的類。

下面的例子給出了如何在組件中設(shè)置 ?@Output()?,來把數(shù)據(jù)從 HTML 的 ?<input>? 推送到父組件的數(shù)組中。

要使用 ?@Output()? ,就必須配置父組件和子組件。

配置子組件

下面的例子中有一個 ?<input>? ,用戶可以輸入一個值,然后點(diǎn)擊一個引發(fā)事件 ?<button>? 然后, ?EventEmitter ?數(shù)據(jù)中繼到父組件。

  1. 在子組件類中導(dǎo)入 ?Output ?和 ?EventEmitter?
  2. import { Output, EventEmitter } from '@angular/core';
  3. 在組件類中,用 ?@Output()? 裝飾一個屬性。下面的例子中 ?newItemEvent ?這個 ?@Output()? 的類型為 ?EventEmitter ?,這意味著它是一個事件。
  4. @Output() newItemEvent = new EventEmitter<string>();

    上述聲明中的差異點(diǎn)如下:

    • ?@Output()? - 一個裝飾器函數(shù),它把該屬性標(biāo)記為數(shù)據(jù)從子組件進(jìn)入父組件的一種途徑
    • ?newItemEvent ?- 這個 ?@Output()? 的名字
    • ?EventEmitter<string>? - 這個 ?@Output()? 的類型
    • ?new EventEmitter<string>()? - 使用 Angular 來創(chuàng)建一個新的事件發(fā)射器,它發(fā)出的數(shù)據(jù)是 ?string ?類型的。
  5. 在同一個組件類中創(chuàng)建一個 ?addNewItem()? 方法:
  6. export class ItemOutputComponent {
    
      @Output() newItemEvent = new EventEmitter<string>();
    
      addNewItem(value: string) {
        this.newItemEvent.emit(value);
      }
    }

    ?addNewItem()? 函數(shù)使用 ?newItemEvent ?這個 ?@Output()? 來引發(fā)一個事件,該事件帶有用戶輸入到 ?<input>? 中的值。

配置子組件的模板

子組件的模板有兩個控件。第一個是帶有模板引用變量 ?#newItem? 的 ?<input>?,用戶可在其中輸入條目名稱。 ?#newItem? 變量的 ?value ?屬性存儲了用戶輸入到 ?<input>? 中的值。

<label for="item-input">Add an item:</label>
<input type="text" id="item-input" #newItem>
<button (click)="addNewItem(newItem.value)">Add to parent's list</button>

第二個元素是帶有 ?click ?事件綁定 的 ?<button>? 元素。

?(click) ?事件綁定到了子組件類中 ?addNewItem()? 方法。?addNewItem()? 方法接受一個 ?#newItem.value? 屬性的值作為參數(shù)。

配置父組件

此范例中的 ?AppComponent ?有一個 ?items ?列表,以及一個向數(shù)組中添加更多條目的方法。

export class AppComponent {
  items = ['item1', 'item2', 'item3', 'item4'];

  addItem(newItem: string) {
    this.items.push(newItem);
  }
}

?addItem()? 方法接受一個字符串形式的參數(shù),然后把該字符串添加到 ?items ?數(shù)組中。

配置父組件的模板

  1. 在父模板中,把父組件的方法綁定到子組件的事件上。
  2. 把子組件選擇器(?<app-item-output>?)放在父組件的模板 ?app.component.html? 中。
  3. <app-item-output (newItemEvent)="addItem($event)"></app-item-output>

    事件綁定 ?(newItemEvent)='addItem($event)' ?會把子組件中的 ?newItemEvent ?事件連接到父組件的 ?addItem()? 方法。

    ?$event? 中包含用戶在子組件模板上的 ?<input>? 中鍵入的數(shù)據(jù)。

    要了解 ?@Output()? 的工作方式,你可以把以下內(nèi)容添加到父組件的模板中:

    <ul>
      <li *ngFor="let item of items">{{item}}</li>
    </ul>

    ?*ngFor? 會迭代 ?items ?數(shù)組中的條目。當(dāng)你在子組件的 ?<input>? 中輸入一個值并單擊該按鈕時,子組件就會發(fā)出該事件,而父組件的 ?addItem()? 方法會把這個值追加到其 ?items ?數(shù)組中,并且列表中會渲染出這個新條目。

同時使用 @Input() 和 @Output()

可以在同一個子組件上使用 ?@Input()? 和 ?@Output()?,范例如下:

<app-input-output
  [item]="currentItem"
  (deleteRequest)="crossOffItem($event)">
</app-input-output>

目標(biāo) ?item ?是子組件類中的一個 ?@Input()? 屬性,它會從父組件的 ?currentItem ?屬性中獲取它的值。當(dāng)你單擊“刪除”時,子組件就會引發(fā)一個事件 ?deleteRequest ?,它會作為父組件中 ?crossOffItem()? 方法的參數(shù)。

下圖展示了子組件 ?<app-input-output>? 中 ?@Input()? 和 ?@Output()? 的各個部分。

input-output-diagram

這里的子選擇器是 ?<app-input-output>?,它所帶的 ?item ?和 ?deleteRequest ?是子組件類中的 ?@Input()? 和 ?@Output()? 屬性。而 ?currentItem ?屬性和 ?crossOffItem()? 方法都位于父組件類中。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號