99re热这里只有精品视频,7777色鬼xxxx欧美色妇,国产成人精品一区二三区在线观看,内射爽无广熟女亚洲,精品人妻av一区二区三区

Angular9 瀏覽組件樹

2020-07-03 18:22 更新

應用的組件之間經(jīng)常需要共享信息。你通常要用松耦合的技術來共享信息,比如數(shù)據(jù)綁定和服務共享。但是有時候讓一個組件直接引用另一個組件還是很有意義的。 例如,你需要通過另一個組件的直接引用來訪問其屬性或調(diào)用其方法。

在 Angular 中獲取組件引用略微有些棘手。 Angular 組件本身并沒有一棵可以用編程方式檢查或瀏覽的樹。 其父子關系是通過組件的視圖對象間接建立的。

每個組件都有一個宿主視圖和一些內(nèi)嵌視圖。 組件 A 的內(nèi)嵌視圖可以是組件 B 的宿主視圖,而組件 B 還可以有它自己的內(nèi)嵌視圖。 這意味著每個組件都有一棵以該組件的宿主視圖為根節(jié)點的視圖樹。

有一些用于在視圖樹中向下導航的 API。 請到 API 參考手冊中查看 Query、QueryList、ViewChildren 和 ContentChildren。

不存在用于獲取父引用的公共 API。 不過,由于每個組件的實例都會添加到注入器的容器中,因此你可以通過 Angular 的依賴注入來訪問父組件。

本節(jié)描述的就是關于這種做法的一些技巧。

查找已知類型的父組件

你可以使用標準的類注入形式來獲取類型已知的父組件。

在下面的例子中,父組件 AlexComponent 具有一些子組件,包括 CathyComponent

Path:"parent-finder.component.ts (AlexComponent v.1)" 。

@Component({
  selector: 'alex',
  template: `
    <div class="a">
      <h3>{{name}}</h3>
      <cathy></cathy>
      <craig></craig>
      <carol></carol>
    </div>`,
})
export class AlexComponent extends Base
{
  name = 'Alex';
}

在把 AlexComponent 注入到 CathyComponent 的構造函數(shù)中之后,Cathy 可以報告她是否能訪問 Alex

Path:"parent-finder.component.ts (CathyComponent)" 。

@Component({
  selector: 'cathy',
  template: `
  <div class="c">
    <h3>Cathy</h3>
    {{alex ? 'Found' : 'Did not find'}} Alex via the component class.<br>
  </div>`
})
export class CathyComponent {
  constructor( @Optional() public alex?: AlexComponent ) { }
}

注意,雖然為了安全起見我們用了 @Optional 限定符,但是范例中仍然會確認 alex 參數(shù)是否有值。

不能根據(jù)父組件的基類訪問父組件

如果你不知道具體的父組件類怎么辦?

可復用組件可能是多個組件的子組件。想象一個用于渲染相關金融工具的突發(fā)新聞的組件。 出于商業(yè)原因,當市場上的數(shù)據(jù)流發(fā)生變化時,這些新組件會頻繁調(diào)用其父組件。

該應用可能定義了十幾個金融工具組件。理想情況下,它們?nèi)紝崿F(xiàn)了同一個基類,你的 NewsComponent 也能理解其 API。

如果能查找實現(xiàn)了某個接口的組件當然更好。 但那是不可能的。因為 TypeScript 接口在轉譯后的 JavaScript 中不存在,而 JavaScript 不支持接口。 因此,找無可找。

這個設計并不怎么好。 該例子是為了驗證組件是否能通過其父組件的基類來注入父組件。

這個例子中的 CraigComponent 體現(xiàn)了此問題。往回看,你可以看到 Alex 組件擴展(繼承)了基類 Base。

Path:"parent-finder.component.ts (Alex class signature)" 。

export class AlexComponent extends Base

CraigComponent 試圖把 Base 注入到它的構造函數(shù)參數(shù) alex 中,并匯報這次注入是否成功了。

Path:"parent-finder.component.ts (CraigComponent)" 。

@Component({
  selector: 'craig',
  template: `
  <div class="c">
    <h3>Craig</h3>
    {{alex ? 'Found' : 'Did not find'}} Alex via the base class.
  </div>`
})
export class CraigComponent {
  constructor( @Optional() public alex?: Base ) { }
}

不幸的是,這不行! 范例確認了 alex 參數(shù)為空。 因此,你不能通過父組件的基類注入它。

根據(jù)父組件的類接口查找它

你可以通過父組件的類接口來查找它。

該父組件必須合作,以類接口令牌為名,為自己定義一個別名提供者。

回憶一下,Angular 總是會把組件實例添加到它自己的注入器中,因此以前你才能把 Alex 注入到 Cathy 中。

編寫一個 別名提供者(一個 provide 對象字面量,其中有一個 useExisting 定義),創(chuàng)造了另一種方式來注入同一個組件實例,并把那個提供者添加到 AlexComponent @Component() 元數(shù)據(jù)的 providers 數(shù)組中。

Path:"parent-finder.component.ts (AlexComponent providers)" 。

providers: [{ provide: Parent, useExisting: forwardRef(() => AlexComponent) }],

Parent 是該提供者的類接口。 forwardRef 用于打破循環(huán)引用,因為在你剛才這個定義中 AlexComponent 引用了自身。

Alex 的第三個子組件 Carol,把其父組件注入到了自己的 parent 參數(shù)中 —— 和你以前做過的一樣。

Path:"parent-finder.component.ts (CarolComponent class)" 。

export class CarolComponent {
  name = 'Carol';
  constructor( @Optional() public parent?: Parent ) { }
}

下面是 Alex 及其家人的運行效果。

使用 @SkipSelf() 在樹中查找父組件

想象一下組件樹的一個分支:Alice -> Barry -> Carol。 無論 Alice 還是 Barry 都實現(xiàn)了類接口 Parent。

Barry 很為難。他需要訪問他的母親 Alice,同時他自己還是 Carol 的父親。 這意味著他必須同時注入 Parent 類接口來找到 Alice,同時還要提供一個 Parent 來滿足 Carol 的要求。

Barry 的代碼如下。

Path:"parent-finder.component.ts (BarryComponent)" 。

const templateB = `
  <div class="b">
    <div>
      <h3>{{name}}</h3>
      <p>My parent is {{parent?.name}}</p>
    </div>
    <carol></carol>
    <chris></chris>
  </div>`;


@Component({
  selector:   'barry',
  template:   templateB,
  providers:  [{ provide: Parent, useExisting: forwardRef(() => BarryComponent) }]
})
export class BarryComponent implements Parent {
  name = 'Barry';
  constructor( @SkipSelf() @Optional() public parent?: Parent ) { }
}

Barryproviders 數(shù)組看起來和 Alex 的一樣。 如果你準備繼續(xù)像這樣編寫別名提供者,就應該創(chuàng)建一個輔助函數(shù)。

現(xiàn)在,注意看 Barry 的構造函數(shù)。

//Barry's constructor


constructor( @SkipSelf() @Optional() public parent?: Parent ) { }

//Carol's constructor


constructor( @Optional() public parent?: Parent ) { }

除增加了 @SkipSelf 裝飾器之外,它和 Carol 的構造函數(shù)相同。

使用 @SkipSelf 有兩個重要原因:

它告訴注入器開始從組件樹中高于自己的位置(也就是父組件)開始搜索 Parent 依賴。

如果你省略了 @SkipSelf 裝飾器,Angular 就會拋出循環(huán)依賴錯誤。

Cannot instantiate cyclic dependency! (BethComponent -> Parent -> BethComponent)

下面是 Alice、Barry 及其家人的運行效果。

父類接口

類接口是一個抽象類,它實際上用做接口而不是基類。

下面的例子定義了一個類接口 Parent。

Path:"parent-finder.component.ts (Parent class-interface)" 。

export abstract class Parent { name: string; }

Parent 類接口定義了一個帶類型的 name 屬性,但沒有實現(xiàn)它。 這個 name 屬性是父組件中唯一可供子組件調(diào)用的成員。 這樣的窄化接口幫助把子組件從它的父組件中解耦出來。

一個組件想要作為父組件使用,就應該像 AliceComponent 那樣實現(xiàn)這個類接口。

Path:"parent-finder.component.ts (AliceComponent class signature)" 。

export class AliceComponent implements Parent

這樣做可以增加代碼的清晰度,但在技術上并不是必要的。 雖然 AlexComponentBase 類所要求的一樣具有 name 屬性,但它的類簽名中并沒有提及 Parent。

Path:"parent-finder.component.ts (AlexComponent class signature)" 。

export class AlexComponent extends Base

provideParent() 輔助函數(shù)

你很快就會厭倦為同一個父組件編寫別名提供者的變體形式,特別是帶有 forwardRef 的那種。

Path:"dependency-injection-in-action/src/app/parent-finder.component.ts" 。

providers: [{ provide: Parent, useExisting: forwardRef(() => AlexComponent) }],

你可以像把這些邏輯抽取到輔助函數(shù)中,就像這樣。

Path:"dependency-injection-in-action/src/app/parent-finder.component.ts" 。

// Helper method to provide the current component instance in the name of a `parentType`.
export function provideParent
  (component: any) {
    return { provide: Parent, useExisting: forwardRef(() => component) };
  }

現(xiàn)在,你可以為組件添加一個更簡單、更有意義的父組件提供者。

Path:"dependency-injection-in-action/src/app/parent-finder.component.ts" 。

providers:  [ provideParent(AliceComponent) ]

你還可以做得更好。當前版本的輔助函數(shù)只能為類接口 Parent 定義別名。 應用可能具有多種父組件類型,每個父組件都有自己的類接口令牌。

這是一個修訂后的版本,它默認為 parent,但是也能接受另一個父類接口作為可選的第二參數(shù)。

Path:"dependency-injection-in-action/src/app/parent-finder.component.ts" 。

// Helper method to provide the current component instance in the name of a `parentType`.
// The `parentType` defaults to `Parent` when omitting the second parameter.
export function provideParent
  (component: any, parentType?: any) {
    return { provide: parentType || Parent, useExisting: forwardRef(() => component) };
  }

下面是針對不同父組件類型的用法。

Path:"dependency-injection-in-action/src/app/parent-finder.component.ts" 。

providers:  [ provideParent(BethComponent, DifferentParent) ]
以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號