溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何使用Angular CDK Portal創建動態內容

發布時間:2021-08-17 11:29:12 來源:億速云 閱讀:187 作者:小新 欄目:web開發

這篇文章將為大家詳細講解有關如何使用Angular CDK Portal創建動態內容,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

Angular 官方提供了一套組件開發套件 Component Dev Kit (CDK),作為各種 Angular 組件開發的基礎工具,其中就提供 “Portal(傳送門)” 來輔助動態視圖的創建。

這個 ”動態視圖“ 可以是組件、TemplateRef 或者 DOM 元素,分別對應三種 Portal 類型(ComponentPortal、TemplatePortal、DomPortal)。它們三個的抽象泛型基類是 Portal<T>,有三個方法:attach(掛載到容器)、detach(從容器移除)、isAttached(判斷視圖是否是掛載狀態)。

而容器也是由一個抽象類 BasePortalOutlet 定義,和視圖類似,包含 attach(給容器掛載視圖)、detach(從容器移除視圖)、dispose(銷毀容器)、isAttached(是否有掛載視圖)。它的主要實現是 DomPortalOutlet 類。用以掛載三種類型的動態視圖。

創建動態內容

先來看看三種動態視圖的創建。

ComponentPortal

相比原生 API,要創建一個動態組件非常的簡單,只需要把組件類傳入 ComponentPortal 構造函數即可。

this.componentPortal = new ComponentPortal(ExampleComponent);

可以傳入任意自定義的組件類,用以創建 ComponentPortal 對象,再動態插入視圖中。

?注意:Angular 9 后的版本推薦使用 Ivy 編譯器,如果是老版本編譯器,傳入的組件類,需要在 Module 的 entryComponents 中聲明,并且這個 Module 不能懶加載。

TemplatePortal

TemplatePortal 的構建,相比組件,多了一個參數(ViewContainerRef)??催^前一篇應該對它非常熟悉了,需要依賴它調用 createEmbeddedView() 來創建嵌入視圖。這里通過構造注入,直接使用當前組件的 ViewContainerRef 實例。

<ng-template #testTemplate>
  <p>一些需要動態插入的內容.</p>
</ng-template>
@ViewChild('testTemplate') templatePortalContent: TemplateRef<any>;

constructor(private _viewContainerRef: ViewContainerRef) { }

ngAfterViewInit() {
  this.templatePortal = new TemplatePortal(
    this.templatePortalContent,
    this._viewContainerRef
  );
}

除了通過構造函數,TemplatePortal 也有一個指令(CdkPortal)可以便捷創建。

<ng-template cdkPortal>
  <p>一些需要動態插入的內容.</p>
</ng-template>

<!-- 或寫作 -->

<!-- 和上面寫法是一致的效果 -->
<p *cdkPortal>
  一些需要動態插入的內容.
</p>

然后通過 @ViewChild 就可以獲得 TemplatePortal 的實例了。

DomPortal

就像上面的示例通過 @ViewChild 獲取 Template 實例來創建,類似的也可以獲取 ElementRef 來創建動態的 DOM。

<div #domPortalContent><span>原生DOM內容</span></div>
@ViewChild('domPortalContent') domPortalContent: ElementRef<HTMLElement>;
ngAfterViewInit() {
  this.domPortal = new DomPortal(this.domPortalContent);
}

可以動態的將這段 DOM 轉移到任意位置。要注意的是,轉移之后,原來的數據綁定,或者綁定的指令可能不會再繼續更新。

插入容器

前面三種類型的 Portal 都說了可以渲染到任意位置,那具體怎么渲染呢?

CdkPortOutlet

最簡單的就是通過 CdkPortOutlet 指令了:

<div>
  <ng-template [cdkPortalOutlet]="anyPortal"></ng-template>
</div>

anyPortal 傳值上面三個中任意的 Portal 實例,都會動態渲染到當前位置。

和原生 API 的指令不同,它可以自動判斷是什么類型的 Portal。另外,它還有個額外的事件:attached,通過這個事件,可以獲取到掛載的組件實例,或者 TemplateRef。這也讓和掛載組件的交互變得十分方便了。

構造容器實例

不過既然說了是可以渲染到任意位置,那自然也包括 Angular 應用外部,要渲染到應用之外,就需要咱們通過構造函數創建容器實例。

這個容器類就是 DomPortalOutlet,它是 PortalOutlet 的實現子類。它的構造參數主要是:Element(掛載視圖的DOM節點)、ComponentFactoryResolver(和上篇一樣,用以動態構建組件)、appRef(當前 Angular 應用的整體實例)、Injector(注入器,用于傳遞依賴)。

constructor(
  private viewContainerRef: ViewContainerRef,
  @Inject(DOCUMENT) private document: any,
  private injector: Injector,
  private componentFactoryResolver: ComponentFactoryResolver
) {
  // 在<body>下創建外部宿主元素
  const container = this.document.createElement('div');
  container.classList.add('outside-portal-container');
  this.outsideContainer = this.document.body.appendChild(container);
  // 獲取應用實例
  this.appRef = this.injector.get(ApplicationRef);
  // 創建外部容器
  this.outsideOutlet = new DomPortalOutlet(
    this.outsideContainer, 
    this.componentFactoryResolver, 
    this.appRef, 
    this.injector
  );
}

// 在應用外部插入動態組件。
openComponentPortalOutSideAngularContext(): void {
  const componentPortal = new ComponentPortal(AlertComponent);
  const componentRef = this.outsideOutlet.attach(componentPortal);
    componentRef.instance.closeAlert.subscribe(() => {
      this.outsideOutlet.detach();
    });
}

// 在應用外部插入動態模板。
openTemplatePortalInsideAngularContext(): void {
  const templatePortal = new TemplatePortal(this.templatePortalContent, this.viewContainerRef);
  this.outsideOutlet.attach(templatePortal);
}

除了掛載視圖到應用外的 DOM 元素中,還需要能夠跟視圖進行數據交互,組件可以通過注入依賴,模板可以傳入上下文對象。

const injectionToken = new InjectionToken<any>('Sharing data with outside component portal');
const customInjector = Injector.create({ providers: [{ provide: CustomInjectionToken, useValue: 'test value' }] });

對創建 outsideContainer 的代碼稍作修改,把這個 customInjector 作為參數傳入(而不是使用當前組件的 injector)

// 重點是第四個參數
new DomPortalOutlet(this.outsideContainer, this.componentFactoryResolver, this.appRef, customInjector);

相應的,這個組件只需要按這個 injectionToken 注入依賴即可:

constructor(@Inject(injectionToken) public customData: any) {}

給模板傳遞上下文就比較簡單了,在創建 TemplatePortal 對象時,傳入上下文對象即可:

// 重點是第三個參數
new TemplatePortal(this.templatePortalContent, this.viewContainerRef, { customData:'test values' });

關于“如何使用Angular CDK Portal創建動態內容”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女